Browse Source

Merge branch 'AvaloniaUI:master' into master

feature/pen-eraser-detection
Krzysztof Krysiński 9 months ago
committed by GitHub
parent
commit
df1601baa0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      Avalonia.Desktop.slnf
  2. 64
      Avalonia.sln
  3. 4
      CONTRIBUTING.md
  4. 4
      Directory.Build.props
  5. 40
      api/Avalonia.Win32.Interoperability.nupkg.xml
  6. 268
      api/Avalonia.nupkg.xml
  7. 17
      azure-pipelines-integrationtests.yml
  8. 34
      azure-pipelines.yml
  9. 12
      build/Base.props
  10. 2
      build/Moq.props
  11. 5
      build/ReactiveUI.props
  12. 16
      build/TargetFrameworks.props
  13. 5
      build/UnitTests.NetCore.targets
  14. 2
      build/XUnit.props
  15. 2
      dirs.proj
  16. 3
      docs/build.md
  17. 2
      external/XamlX
  18. 2
      global.json
  19. 2
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  20. 32
      native/Avalonia.Native/src/OSX/automation.mm
  21. 77
      native/Avalonia.Native/src/OSX/clipboard.mm
  22. 20
      nukebuild/ApiDiffHelper.cs
  23. 13
      nukebuild/Build.cs
  24. 4
      nukebuild/_build.csproj
  25. 12
      packages/Avalonia/Avalonia.csproj
  26. 3
      packages/Avalonia/Avalonia.props
  27. 2
      packages/Avalonia/AvaloniaPrivateApis.targets
  28. 2
      packages/Avalonia/AvaloniaSingleProject.targets
  29. 2
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  30. 10
      samples/ControlCatalog.Browser.Blazor/App.razor
  31. 10
      samples/ControlCatalog.Browser.Blazor/App.razor.cs
  32. 29
      samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj
  33. 5
      samples/ControlCatalog.Browser.Blazor/Pages/Index.razor
  34. 39
      samples/ControlCatalog.Browser.Blazor/Program.cs
  35. 22
      samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json
  36. 7
      samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor
  37. 10
      samples/ControlCatalog.Browser.Blazor/_Imports.razor
  38. 56
      samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css
  39. BIN
      samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico
  40. 22
      samples/ControlCatalog.Browser.Blazor/wwwroot/index.html
  41. 35
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  42. 2
      samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs
  43. 2
      samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs
  44. 0
      samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes-license.md
  45. 0
      samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes.mp4
  46. 2
      samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs
  47. 2
      samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs
  48. 2
      samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs
  49. 2
      samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs
  50. 172
      samples/ControlCatalog.Desktop/Program.cs
  51. 2
      samples/ControlCatalog.Desktop/Properties/launchSettings.json
  52. 0
      samples/ControlCatalog.Desktop/app.manifest
  53. 2
      samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj
  54. 41
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  55. 180
      samples/ControlCatalog.NetCore/Program.cs
  56. 2
      samples/ControlCatalog/ControlCatalog.csproj
  57. 6
      samples/ControlCatalog/Pages/ClipboardPage.xaml
  58. 31
      samples/ControlCatalog/Pages/ClipboardPage.xaml.cs
  59. 6
      samples/ControlCatalog/Pages/DragAndDropPage.xaml
  60. 26
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  61. 4
      samples/Directory.Build.props
  62. 4
      samples/Generators.Sandbox/App.xaml.cs
  63. 37
      samples/Generators.Sandbox/Controls/SignUpView.xaml
  64. 39
      samples/Generators.Sandbox/Controls/SignUpView.xaml.cs
  65. 14
      samples/Generators.Sandbox/Generators.Sandbox.csproj
  66. 2
      samples/Generators.Sandbox/Program.cs
  67. 102
      samples/Generators.Sandbox/ViewModels/SignUpViewModel.cs
  68. 15
      samples/Generators.Sandbox/Views/SignUpView.xaml.cs
  69. 4
      samples/GpuInterop/App.axaml.cs
  70. 187
      samples/GpuInterop/D3DDemo/D3D11DemoControl.cs
  71. 80
      samples/GpuInterop/D3DDemo/D3D11Swapchain.cs
  72. 224
      samples/GpuInterop/D3DDemo/D3DContent.cs
  73. 7
      samples/GpuInterop/DemoType.cs
  74. 14
      samples/GpuInterop/GpuInterop.csproj
  75. 10
      samples/GpuInterop/MainWindow.axaml
  76. 22
      samples/GpuInterop/MainWindow.axaml.cs
  77. 32
      samples/GpuInterop/Program.cs
  78. 12
      samples/GpuInterop/Properties/launchSettings.json
  79. 117
      samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs
  80. 4
      samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs
  81. 18
      samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs
  82. 43
      samples/GpuInterop/VulkanDemo/VulkanContent.cs
  83. 33
      samples/GpuInterop/VulkanDemo/VulkanContext.cs
  84. 49
      samples/GpuInterop/VulkanDemo/VulkanImage.cs
  85. 2
      samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs
  86. 8
      samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs
  87. 8
      samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs
  88. 2
      samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs
  89. 7
      samples/IntegrationTestApp/MainWindow.axaml
  90. 2
      samples/IntegrationTestApp/bundle.sh
  91. 2
      samples/MiniMvvm/MiniMvvm.csproj
  92. 8
      samples/ReactiveUIDemo/App.axaml
  93. 37
      samples/ReactiveUIDemo/App.axaml.cs
  94. 19
      samples/ReactiveUIDemo/MainWindow.axaml
  95. 22
      samples/ReactiveUIDemo/MainWindow.axaml.cs
  96. 28
      samples/ReactiveUIDemo/ReactiveUIDemo.csproj
  97. 11
      samples/ReactiveUIDemo/ViewModels/BarViewModel.cs
  98. 11
      samples/ReactiveUIDemo/ViewModels/FooViewModel.cs
  99. 9
      samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs
  100. 21
      samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs

3
Avalonia.Desktop.slnf

@ -10,7 +10,6 @@
"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",
@ -32,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",
@ -65,7 +63,6 @@
"tests\\Avalonia.LeakTests\\Avalonia.LeakTests.csproj",
"tests\\Avalonia.Markup.UnitTests\\Avalonia.Markup.UnitTests.csproj",
"tests\\Avalonia.Markup.Xaml.UnitTests\\Avalonia.Markup.Xaml.UnitTests.csproj",
"tests\\Avalonia.ReactiveUI.UnitTests\\Avalonia.ReactiveUI.UnitTests.csproj",
"tests\\Avalonia.RenderTests.WpfCompare\\Avalonia.RenderTests.WpfCompare.csproj",
"tests\\Avalonia.Skia.RenderTests\\Avalonia.Skia.RenderTests.csproj",
"tests\\Avalonia.Skia.UnitTests\\Avalonia.Skia.UnitTests.csproj",

64
Avalonia.sln

@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Simple", "src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}"
@ -23,10 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.UnitTests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.Direct2D1.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}"
@ -46,8 +40,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DE
src\Shared\StreamCompatibilityExtensions.cs = src\Shared\StreamCompatibilityExtensions.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}"
@ -88,8 +80,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Android", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.csproj", "{7D2D3083-71DD-4CC9-8907-39A0D86FB322}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "samples\ControlCatalog.NetCore\ControlCatalog.NetCore.csproj", "{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
build\AvaloniaPublicKey.props = build\AvaloniaPublicKey.props
@ -108,12 +98,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\NetCore.props = build\NetCore.props
build\NetFX.props = build\NetFX.props
build\NullableEnable.props = build\NullableEnable.props
build\ReactiveUI.props = build\ReactiveUI.props
build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\Rx.props = build\Rx.props
build\SampleApp.props = build\SampleApp.props
build\SharedVersion.props = build\SharedVersion.props
build\SharpDX.props = build\SharpDX.props
build\SkiaSharp.props = build\SkiaSharp.props
build\SourceGenerators.props = build\SourceGenerators.props
build\SourceLink.props = build\SourceLink.props
@ -171,8 +159,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.X11", "src\Avaloni
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformSanityChecks", "samples\PlatformSanityChecks\PlatformSanityChecks.csproj", "{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.UnitTests", "tests\Avalonia.ReactiveUI.UnitTests\Avalonia.ReactiveUI.UnitTests.csproj", "{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Dialogs", "src\Avalonia.Dialogs\Avalonia.Dialogs.csproj", "{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src\Avalonia.FreeDesktop\Avalonia.FreeDesktop.csproj", "{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}"
@ -217,14 +203,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SingleProjectSandbox", "sam
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser", "src\Browser\Avalonia.Browser\Avalonia.Browser.csproj", "{4A39637C-9338-4925-A4DB-D072E292EC78}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Browser.Blazor", "src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj", "{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser", "samples\ControlCatalog.Browser\ControlCatalog.Browser.csproj", "{15B93A4C-1B46-43F6-B534-7B25B6E99932}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Browser.Blazor", "samples\ControlCatalog.Browser.Blazor\ControlCatalog.Browser.Blazor.csproj", "{90B08091-9BBD-4362-B712-E9F2CC62B218}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\ReactiveUIDemo\ReactiveUIDemo.csproj", "{75C47156-C5D8-44BC-A5A7-E8657C2248D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
@ -320,10 +300,6 @@ Global
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -344,14 +320,6 @@ Global
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -360,10 +328,6 @@ Global
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -430,10 +394,6 @@ Global
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.Build.0 = Release|Any CPU
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.Build.0 = Release|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -496,10 +456,6 @@ Global
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.Build.0 = Release|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -584,22 +540,10 @@ Global
{4A39637C-9338-4925-A4DB-D072E292EC78}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A39637C-9338-4925-A4DB-D072E292EC78}.Release|Any CPU.Build.0 = Release|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D}.Release|Any CPU.Build.0 = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15B93A4C-1B46-43F6-B534-7B25B6E99932}.Release|Any CPU.Build.0 = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90B08091-9BBD-4362-B712-E9F2CC62B218}.Release|Any CPU.Build.0 = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75C47156-C5D8-44BC-A5A7-E8657C2248D6}.Release|Any CPU.Build.0 = Release|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C810060E-3809-4B74-A125-F11533AF9C1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -722,11 +666,8 @@ Global
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}
@ -745,7 +686,6 @@ Global
{F1FDC5B0-4654-416F-AE69-E3E9BBD87801} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
@ -757,7 +697,6 @@ Global
{3C471044-3640-45E3-B1B2-16D2FF8399EE} = {E870DCD7-F46A-498D-83FC-D0FD13E0A11C}
{41B02319-965D-4945-8005-C1A3D1224165} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{4D36CEC8-53F2-40A5-9A37-79AAE356E2DA} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC} = {FF237916-7150-496B-89ED-6CA3292896E7}
{B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E} = {FF237916-7150-496B-89ED-6CA3292896E7}
@ -775,10 +714,7 @@ Global
{1BBFAD42-B99E-47E0-B00A-A4BC6B6BB4BB} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{3B8519C1-2F51-4F12-A348-120AB91D4532} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{4A39637C-9338-4925-A4DB-D072E292EC78} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{47F8530C-F19B-4B1A-B4D6-EB231522AE5D} = {86A3F706-DC3C-43C6-BE1B-B98F5BAAA268}
{15B93A4C-1B46-43F6-B534-7B25B6E99932} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{90B08091-9BBD-4362-B712-E9F2CC62B218} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{75C47156-C5D8-44BC-A5A7-E8657C2248D6} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C810060E-3809-4B74-A125-F11533AF9C1B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C692FE73-43DB-49CE-87FC-F03ED61F25C9} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{DDA28789-C21A-4654-86CE-D01E81F095C5} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}

4
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)
For more information see the [Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct)

4
Directory.Build.props

@ -4,11 +4,11 @@
<Import Project="$(MSBuildThisFileDirectory)/build/WarnAsErrors.props" />
<PropertyGroup>
<PackageOutputPath Condition="'$(PackageOutputPath)' == ''">$(MSBuildThisFileDirectory)build-intermediate/nuget</PackageOutputPath>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netstandard2.0\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<!-- https://github.com/dotnet/msbuild/issues/2661 -->
<AddSyntheticProjectReferencesForSolutionDependencies>false</AddSyntheticProjectReferencesForSolutionDependencies>
<RunApiCompat>False</RunApiCompat>
<LangVersion>12</LangVersion>
<LangVersion>14.0</LangVersion>
<CreateHardLinksForCopyAdditionalFilesIfPossible>true</CreateHardLinksForCopyAdditionalFilesIfPossible>
<CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>true</CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>
<CreateHardLinksForCopyLocalIfPossible>true</CreateHardLinksForCopyLocalIfPossible>

40
api/Avalonia.Win32.Interoperability.nupkg.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@)</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@)</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost.PreFilterMessage(System.Windows.Forms.Message@)</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net461/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net6.0-windows7.0/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0008</DiagnosticId>
<Target>T:Avalonia.Win32.Interoperability.WinFormsAvaloniaControlHost</Target>
<Left>baseline/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll</Left>
<Right>current/Avalonia.Win32.Interoperability/lib/net8.0-windows7.0/Avalonia.Win32.Interoperability.dll</Right>
</Suppression>
</Suppressions>

268
api/Avalonia.nupkg.xml

@ -1,24 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:Avalonia.Media.Fonts.FontFamilyLoader</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Dialogs.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Dialogs.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Dialogs.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Dialogs.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Avalonia.Media.Fonts.FontCollectionBase._glyphTypefaceCache</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.IFontCollection.Initialize(Avalonia.Platform.IFontManagerImpl)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Avalonia.Dialogs.Internal.ManagedFileChooserFilterViewModel.#ctor(Avalonia.Platform.Storage.FilePickerFileType)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Dialogs.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Input.Platform.IClipboard.SetDataAsync(Avalonia.Input.IAsyncDataTransfer)</Target>
@ -43,6 +169,12 @@
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)</Target>
@ -97,6 +229,12 @@
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)</Target>
@ -151,6 +289,12 @@
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32,Avalonia.Media.FontStyle,Avalonia.Media.FontWeight,Avalonia.Media.FontStretch,System.String,System.Globalization.CultureInfo,Avalonia.Media.Typeface@)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Avalonia.Platform.IPlatformRenderInterfaceImportedImage.SnapshotWithTimelineSemaphores(Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64,Avalonia.Platform.IPlatformRenderInterfaceImportedSemaphore,System.UInt64)</Target>
@ -181,4 +325,124 @@
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.OpenGL.dll</Right>
</Suppression>
</Suppressions>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Count</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Count</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Count</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Count</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net6.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net6.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Count</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Count</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Count</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.get_Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>M:Avalonia.Media.Fonts.FontCollectionBase.GetEnumerator</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Count</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0012</DiagnosticId>
<Target>P:Avalonia.Media.Fonts.FontCollectionBase.Item(System.Int32)</Target>
<Left>baseline/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Left>
<Right>current/Avalonia/lib/netstandard2.0/Avalonia.Base.dll</Right>
</Suppression>
</Suppressions>

17
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
@ -31,11 +31,10 @@ jobs:
pkill IntegrationTestApp
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
./build.sh CompileNative
sudo xcode-select -s /Applications/Xcode_14.3.app/Contents/Developer
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'
@ -57,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

34
azure-pipelines.yml

@ -2,12 +2,12 @@ jobs:
- job: GetPRNumber
pool:
vmImage: 'ubuntu-22.04'
vmImage: 'ubuntu-24.04'
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
displayName: 'Use .NET 8.0 SDK'
displayName: 'Use .NET 10.0 SDK'
inputs:
packageType: sdk
useGlobalJson: true
@ -23,16 +23,16 @@ jobs:
- job: Linux
pool:
vmImage: 'ubuntu-22.04'
vmImage: 'ubuntu-24.04'
steps:
- task: UseDotNet@2
displayName: 'Use .NET 6.0 Runtime'
displayName: 'Use .NET 8.0 Runtime'
inputs:
packageType: runtime
version: 6.0.x
version: 8.0.x
- task: UseDotNet@2
displayName: 'Use .NET 8.0 SDK'
displayName: 'Use .NET 10.0 SDK'
inputs:
packageType: sdk
useGlobalJson: true
@ -62,16 +62,16 @@ jobs:
variables:
SolutionDir: '$(Build.SourcesDirectory)'
pool:
vmImage: 'macos-13'
vmImage: 'macos-15'
steps:
- task: UseDotNet@2
displayName: 'Use .NET 6.0 Runtime'
displayName: 'Use .NET 8.0 Runtime'
inputs:
packageType: runtime
version: 6.0.x
version: 8.0.x
- task: UseDotNet@2
displayName: 'Use .NET 8.0 SDK'
displayName: 'Use .NET 10.0 SDK'
inputs:
packageType: sdk
useGlobalJson: true
@ -95,11 +95,11 @@ jobs:
inputs:
actions: 'build'
scheme: ''
sdk: 'macosx14.2'
sdk: 'macosx26.0'
configuration: 'Release'
xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
xcodeVersion: 'specifyPath' # Options: 8, 9, default, specifyPath
xcodeDeveloperDir: '/Applications/Xcode_15.2.app/Contents/Developer'
xcodeDeveloperDir: '/Applications/Xcode_26.0.app/Contents/Developer'
args: '-derivedDataPath ./'
- task: CmdLine@2
@ -134,18 +134,18 @@ jobs:
- job: Windows
pool:
vmImage: 'windows-2022'
vmImage: 'windows-2025'
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
displayName: 'Use .NET 6.0 Runtime'
displayName: 'Use .NET 8.0 Runtime'
inputs:
packageType: runtime
version: 6.0.x
version: 8.0.x
- task: UseDotNet@2
displayName: 'Use .NET 8.0 SDK'
displayName: 'Use .NET 10.0 SDK'
inputs:
packageType: sdk
useGlobalJson: true
@ -160,7 +160,7 @@ jobs:
displayName: 'Install Nuke'
inputs:
script: |
dotnet tool install --global Nuke.GlobalTool --version 6.2.1
dotnet tool install --global Nuke.GlobalTool --version 9.0.4
- task: CmdLine@2
displayName: 'Run Nuke'

12
build/Base.props

@ -1,12 +1,8 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- '!NET6_0_OR_GREATER' equivalent -->
<ItemGroup Condition="!('$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '6.0')))">
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<ItemGroup Condition="!('$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '6.0')))">
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="6.0.0" />
</ItemGroup>
<!-- '!NET8_0_OR_GREATER' equivalent -->
<ItemGroup Condition="!('$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '8.0')))">
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.10" />
</ItemGroup>
</Project>

2
build/Moq.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="Moq" Version="4.20.72" />
</ItemGroup>
</Project>

5
build/ReactiveUI.props

@ -1,5 +0,0 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="ReactiveUI" Version="20.1.1" />
</ItemGroup>
</Project>

16
build/TargetFrameworks.props

@ -1,17 +1,17 @@
<Project>
<PropertyGroup>
<AvsCurrentTargetFramework>net8.0</AvsCurrentTargetFramework>
<AvsCurrentTargetFramework>net10.0</AvsCurrentTargetFramework>
<AvsCurrentWindowsTargetFramework>$(AvsCurrentTargetFramework)-windows</AvsCurrentWindowsTargetFramework>
<AvsCurrentMacOSTargetFramework>$(AvsCurrentTargetFramework)-macos</AvsCurrentMacOSTargetFramework>
<AvsCurrentAndroidTargetFramework>$(AvsCurrentTargetFramework)-android34.0</AvsCurrentAndroidTargetFramework>
<AvsCurrentMacCatalystTargetFramework>$(AvsCurrentTargetFramework)-maccatalyst17.0</AvsCurrentMacCatalystTargetFramework>
<AvsCurrentIOSTargetFramework>$(AvsCurrentTargetFramework)-ios17.0</AvsCurrentIOSTargetFramework>
<AvsCurrentTvOSTargetFramework>$(AvsCurrentTargetFramework)-tvos17.0</AvsCurrentTvOSTargetFramework>
<AvsCurrentAndroidTargetFramework>$(AvsCurrentTargetFramework)-android36.0</AvsCurrentAndroidTargetFramework>
<AvsCurrentMacCatalystTargetFramework>$(AvsCurrentTargetFramework)-maccatalyst26.0</AvsCurrentMacCatalystTargetFramework>
<AvsCurrentIOSTargetFramework>$(AvsCurrentTargetFramework)-ios26.0</AvsCurrentIOSTargetFramework>
<AvsCurrentTvOSTargetFramework>$(AvsCurrentTargetFramework)-tvos26.0</AvsCurrentTvOSTargetFramework>
<AvsCurrentBrowserTargetFramework>$(AvsCurrentTargetFramework)-browser</AvsCurrentBrowserTargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(AvsSkipBuildingLegacyTargetFrameworks)' != 'True'">
<AvsLegacyTargetFrameworks>net6.0</AvsLegacyTargetFrameworks>
<AvsLegacyWindowsTargetFrameworks>net6.0-windows</AvsLegacyWindowsTargetFrameworks>
<AvsLegacyTargetFrameworks>net8.0</AvsLegacyTargetFrameworks>
<AvsLegacyWindowsTargetFrameworks>net8.0-windows</AvsLegacyWindowsTargetFrameworks>
</PropertyGroup>
<PropertyGroup>
@ -20,7 +20,7 @@
<AvsMinSupportedIOSVersion>13.0</AvsMinSupportedIOSVersion>
<AvsMinSupportedTvOSVersion>13.0</AvsMinSupportedTvOSVersion>
<AvsMinSupportedMacCatalystVersion>13.1</AvsMinSupportedMacCatalystVersion>
<AvsMinSupportedAndroidVersion>21.0</AvsMinSupportedAndroidVersion>
<AvsMinSupportedAndroidVersion>24.0</AvsMinSupportedAndroidVersion>
<!-- Desktop OS min version is not set in any of ours backends, but only used in some samples. -->
<!-- Avalonia technically supports 10.12. -->
<AvsMinSupportedMacOsVersion>10.15</AvsMinSupportedMacOsVersion>

5
build/UnitTests.NetCore.targets

@ -3,7 +3,4 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Thread" Version="4.3.0" />
</ItemGroup>
</Project>
</Project>

2
build/XUnit.props

@ -8,7 +8,7 @@
<PackageReference Include="xunit.runner.console" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
</ItemGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>

2
dirs.proj

@ -13,9 +13,7 @@
<ProjectReference Remove="samples/*.MacCatalyst/*.csproj" />
<ProjectReference Remove="samples/*.Android/*.csproj" />
<ProjectReference Remove="samples/*.Browser/*.csproj" />
<ProjectReference Remove="samples/*.Blazor/*.csproj" />
<ProjectReference Remove="samples/SingleProjectSandbox/*.csproj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows'))">

3
docs/build.md

@ -71,6 +71,9 @@ And run tests:
Or if you need to create nuget packages as well (it will compile and run tests automatically):
`nuke --target Package --configuration Release`
Alternatively, you can run nuke build direclty without installing Nuke global tool:
`dotnet run --project nukebuild/_build.csproj -- --configuration Debug`
# Linux/macOS
It's *not* possible to build the *whole* project on Linux/macOS. You can only build the subset targeting .NET Standard and .NET Core (which is, however, sufficient to get UI working on Linux/macOS). If you want to something that involves changing platform-specific APIs you'll need a Windows machine.

2
external/XamlX

@ -1 +1 @@
Subproject commit 83567b8a50bbf612a0b1420a3dc6d8e8ebee2399
Subproject commit c32d3040e536ae9768233ea5a445697632578bd0

2
global.json

@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.411",
"version": "10.0.100",
"rollForward": "latestFeature"
},
"msbuild-sdks": {

2
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -485,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;
@ -496,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;

32
native/Avalonia.Native/src/OSX/automation.mm

@ -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());

77
native/Avalonia.Native/src/OSX/clipboard.mm

@ -27,12 +27,11 @@ public:
if (changeCount != [_pasteboard changeCount])
return COR_E_OBJECTDISPOSED;
auto types = [_pasteboard types];
*ret = types == nil ? nullptr : CreateAvnStringArray(types);
*ret = ConvertPasteboardTypes([_pasteboard types]);
return S_OK;
}
virtual HRESULT GetItemCount(int64_t changeCount, int* ret) override
{
START_COM_ARP_CALL;
@ -57,13 +56,36 @@ public:
if (changeCount != [_pasteboard changeCount])
return COR_E_OBJECTDISPOSED;
auto item = [[_pasteboard pasteboardItems] objectAtIndex:index];
auto types = [item types];
*ret = types == nil ? nullptr : CreateAvnStringArray(types);
*ret = ConvertPasteboardTypes([item types]);
return S_OK;
}
static IAvnStringArray* ConvertPasteboardTypes(NSArray<NSPasteboardType> *types)
{
if (types != nil)
{
NSMutableArray<NSString *> *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])
{
if ([mutableTypes containsObject:NSPasteboardTypeTIFF]
|| [mutableTypes containsObject:@"public.jpeg"])
{
[mutableTypes addObject: NSPasteboardTypePNG];
}
}
return CreateAvnStringArray(mutableTypes);
}
return nil;
}
virtual HRESULT GetItemValueAsString(int index, int64_t changeCount, const char* format, IAvnString** ret) override
{
START_COM_ARP_CALL;
@ -91,8 +113,45 @@ public:
return COR_E_OBJECTDISPOSED;
auto item = [[_pasteboard pasteboardItems] objectAtIndex:index];
auto value = [item dataForType:[NSString stringWithUTF8String:format]];
auto formatStr = [NSString stringWithUTF8String:format];
auto value = [item dataForType: formatStr];
// If PNG wasn't found, try to convert TIFF or JPEG to PNG
if (value == nil && [formatStr isEqualToString: NSPasteboardTypePNG])
{
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)
{
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:@{}];
}
}
*ret = value == nil || [value length] == 0
? nullptr
: CreateByteArray((void*)[value bytes], (int)[value length]);

20
nukebuild/ApiDiffHelper.cs

@ -326,25 +326,11 @@ public static class ApiDiffHelper
var frameworkDiffs = new List<FrameworkDiffInfo>();
// Handle frameworks that exist only in the current package.
foreach (var framework in currentFolderNames.Keys.Except(baselineFolderNames.Keys))
{
var folderName = currentFolderNames[framework];
Directory.CreateDirectory(baselineFolderPath / folderName);
baselineFolderNames.Add(framework, folderName);
}
// Handle frameworks that exist only for the baseline package.
foreach (var framework in baselineFolderNames.Keys.Except(currentFolderNames.Keys))
{
var folderName = baselineFolderNames[framework];
Directory.CreateDirectory(currentFolderPath / folderName);
currentFolderNames.Add(framework, folderName);
}
foreach (var (framework, currentFolderName) in currentFolderNames)
{
var baselineFolderName = baselineFolderNames[framework];
// Ignore new frameworks that didn't exist in the baseline package. Empty folders make the ApiDiff tool crash.
if (!baselineFolderNames.TryGetValue(framework, out var baselineFolderName))
continue;
frameworkDiffs.Add(new FrameworkDiffInfo(
framework,

13
nukebuild/Build.cs

@ -240,11 +240,11 @@ partial class Build : NukeBuild
var tfm = fw;
if (tfm == "$(AvsCurrentTargetFramework)")
{
tfm = "net8.0";
tfm = "net10.0";
}
if (tfm == "$(AvsLegacyTargetFrameworks)")
{
tfm = "net6.0";
tfm = "net8.0";
}
if (tfm.StartsWith("net4")
@ -296,7 +296,6 @@ partial class Build : NukeBuild
RunCoreTest("Avalonia.Markup.UnitTests");
RunCoreTest("Avalonia.Markup.Xaml.UnitTests");
RunCoreTest("Avalonia.Skia.UnitTests");
RunCoreTest("Avalonia.ReactiveUI.UnitTests");
RunCoreTest("Avalonia.Headless.NUnit.PerAssembly.UnitTests");
RunCoreTest("Avalonia.Headless.NUnit.PerTest.UnitTests");
RunCoreTest("Avalonia.Headless.XUnit.PerAssembly.UnitTests");
@ -309,8 +308,6 @@ partial class Build : NukeBuild
.Executes(() =>
{
RunCoreTest("Avalonia.Skia.RenderTests");
if (Parameters.IsRunningOnWindows)
RunCoreTest("Avalonia.Direct2D1.RenderTests");
});
Target RunToolsTests => _ => _
@ -416,13 +413,13 @@ partial class Build : NukeBuild
ApiDiffHelper.MergePackageMarkdownDiffFiles(outputFolderPath, baselineDisplay, currentDisplay);
});
Target RunTests => _ => _
.DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests)
.DependsOn(RunToolsTests)
.DependsOn(RunHtmlPreviewerTests)
.DependsOn(RunLeakTests);
.DependsOn(RunHtmlPreviewerTests);
//.DependsOn(RunLeakTests); // dotMemory Unit doesn't support modern .NET versions, see https://youtrack.jetbrains.com/issue/DMU-300/
Target Package => _ => _
.DependsOn(RunTests)

4
nukebuild/_build.csproj

@ -21,8 +21,8 @@
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.14.8" PrivateAssets="All" />
<PackageReference Include="NuGet.Protocol" Version="6.14.0" />
<PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[10.0.100-preview.7.25380.108]" />
<PackageDownload Include="Microsoft.DotNet.ApiDiff.Tool" Version="[10.0.100-rc.1.25414.111]" />
<PackageDownload Include="Microsoft.DotNet.ApiCompat.Tool" Version="[10.0.100]" />
<PackageDownload Include="Microsoft.DotNet.ApiDiff.Tool" Version="[10.0.100-rtm.25531.102]" />
<PackageDownload Include="dotnet-ilrepack" Version="[1.0.0]" />
</ItemGroup>

12
packages/Avalonia/Avalonia.csproj

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks);netstandard2.0</TargetFrameworks>
<TargetFrameworks>$(AvsCurrentTargetFramework);$(AvsLegacyTargetFrameworks)</TargetFrameworks>
<PackageId>Avalonia</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.BuildServices" Version="11.3.1" />
<PackageReference Include="Avalonia.BuildServices" Version="11.3.2" />
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj"
PrivateAssets="all" />
@ -27,13 +27,13 @@
<MSBuild Projects="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj" Properties="Configuration=$(Configuration);&#xA;Platform=$(Platform)" />
<ItemGroup>
<_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netstandard2.0/Avalonia.Designer.HostApp.dll">
<PackagePath>tools/netstandard2.0/designer</PackagePath>
<_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/$(AvsCurrentTargetFramework)/Avalonia.Designer.HostApp.dll">
<PackagePath>tools/$(AvsCurrentTargetFramework)/designer</PackagePath>
<Visible>false</Visible>
<BuildAction>None</BuildAction>
</_PackageFiles>
<_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/net461/Avalonia.Designer.HostApp.exe">
<PackagePath>tools/net461/designer</PackagePath>
<_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/$(AvsLegacyTargetFrameworks)/Avalonia.Designer.HostApp.dll">
<PackagePath>tools/$(AvsLegacyTargetFrameworks)/designer</PackagePath>
<Visible>false</Visible>
<BuildAction>None</BuildAction>
</_PackageFiles>

3
packages/Avalonia/Avalonia.props

@ -1,7 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\designer\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<AvaloniaPreviewerNetFullToolPath>$(MSBuildThisFileDirectory)\..\tools\net461\designer\Avalonia.Designer.HostApp.exe</AvaloniaPreviewerNetFullToolPath>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\..\tools\$(AvsCurrentTargetFramework)\designer\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<AvaloniaBuildTasksLocation>$(MSBuildThisFileDirectory)\..\tools\netstandard2.0\Avalonia.Build.Tasks.dll</AvaloniaBuildTasksLocation>
<UsedAvaloniaProducts>$(UsedAvaloniaProducts);AvaloniaUI</UsedAvaloniaProducts>
<EnableAvaloniaXamlCompilation Condition="'$(EnableAvaloniaXamlCompilation)'==''">true</EnableAvaloniaXamlCompilation>

2
packages/Avalonia/AvaloniaPrivateApis.targets

@ -13,7 +13,7 @@
</Target>
<Target Name="AddReferencePathsToRealAvaloniaAssemblies" BeforeTargets="CoreCompile" Condition="'$(AvaloniaAccessUnstablePrivateApis.ToLowerInvariant())'=='true'">
<PropertyGroup>
<AvaloniaUnstableApiFrameworkToUse>net6.0</AvaloniaUnstableApiFrameworkToUse>
<AvaloniaUnstableApiFrameworkToUse>net8.0</AvaloniaUnstableApiFrameworkToUse>
<AvaloniaUnstableApiFrameworkToUse Condition="$(TargetFramework.StartsWith('net4')) == 'true' or $(TargetFramework.StartsWith('net5')) == 'true' or $(TargetFramework.StartsWith('netsta')) == 'true' or $(TargetFramework.StartsWith('netcore')) == 'true'">netstandard2.0</AvaloniaUnstableApiFrameworkToUse>
</PropertyGroup>
<ItemGroup>

2
packages/Avalonia/AvaloniaSingleProject.targets

@ -98,7 +98,7 @@
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tvos'">13.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'macos'">10.15</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>

2
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -26,7 +26,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.4" />
<PackageReference Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.17" />
</ItemGroup>
<ItemGroup>

10
samples/ControlCatalog.Browser.Blazor/App.razor

@ -1,10 +0,0 @@
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

10
samples/ControlCatalog.Browser.Blazor/App.razor.cs

@ -1,10 +0,0 @@
using System;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Browser.Blazor;
namespace ControlCatalog.Browser.Blazor;
public partial class App
{
}

29
samples/ControlCatalog.Browser.Blazor/ControlCatalog.Browser.Blazor.csproj

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>$(AvsCurrentBrowserTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<Nullable>enable</Nullable>
<EmccTotalMemory>16777216</EmccTotalMemory>
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<BlazorWebAssemblyPreserveCollationData>false</BlazorWebAssemblyPreserveCollationData>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.2" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Browser\Avalonia.Browser.Blazor\Avalonia.Browser.Blazor.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.props" />
<Import Project="..\..\src\Browser\Avalonia.Browser\build\Avalonia.Browser.targets" />
</Project>

5
samples/ControlCatalog.Browser.Blazor/Pages/Index.razor

@ -1,5 +0,0 @@
@page "/"
@using Avalonia.Browser.Blazor
<AvaloniaView />

39
samples/ControlCatalog.Browser.Blazor/Program.cs

@ -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<ControlCatalog.App>()
.StartBlazorAppAsync();
}
public static WebAssemblyHostBuilder CreateHostBuilder(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
return builder;
}
}

22
samples/ControlCatalog.Browser.Blazor/Properties/launchSettings.json

@ -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"
}
}
}
}

7
samples/ControlCatalog.Browser.Blazor/Shared/MainLayout.razor

@ -1,7 +0,0 @@
@inherits LayoutComponentBase
<div class="page">
<div class="main">
@Body
</div>
</div>

10
samples/ControlCatalog.Browser.Blazor/_Imports.razor

@ -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

56
samples/ControlCatalog.Browser.Blazor/wwwroot/css/app.css

@ -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%;
}

BIN
samples/ControlCatalog.Browser.Blazor/wwwroot/favicon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

22
samples/ControlCatalog.Browser.Blazor/wwwroot/index.html

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Avalonia Sample</title>
<base href="/" />
<link href="css/app.css" rel="stylesheet" />
</head>
<body>
<div id="app">Powered by Avalonia</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

35
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -1,22 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<OutputType>WinExe</OutputType>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>../ControlCatalog.NetCore/app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
<Compile Include="..\..\src\Avalonia.X11\Interop\Glib.cs" Link="NativeControls\Gtk\Glib.cs" />
<Compile Include="..\..\src\Avalonia.Base\Platform\Interop\Utf8Buffer.cs" Link="NativeControls\Utf8Buffer.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="NativeControls\Gtk\nodes.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="..\ControlCatalog.NetCore\NativeControls\Win\*.cs" Link="NativeControls\*" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<!-- For native controls test -->
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
</ItemGroup>
<PropertyGroup>
<!-- For Microsoft.CodeAnalysis -->
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
</Project>

2
samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs → samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs

@ -5,7 +5,7 @@ using Avalonia.Controls.Platform;
using System;
using ControlCatalog.Pages;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
public class EmbedSampleGtk : INativeDemoControl
{

2
samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs → samples/ControlCatalog.Desktop/NativeControls/Gtk/GtkHelper.cs

@ -7,7 +7,7 @@ using Avalonia.X11.NativeDialogs;
using static Avalonia.X11.NativeDialogs.Gtk;
using static Avalonia.X11.Interop.Glib;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
internal class GtkHelper
{

0
samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes-license.md → samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes-license.md

0
samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes.mp4 → samples/ControlCatalog.Desktop/NativeControls/Gtk/nodes.mp4

2
samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs → samples/ControlCatalog.Desktop/NativeControls/Mac/EmbedSample.Mac.cs

@ -8,7 +8,7 @@ using ControlCatalog.Pages;
using MonoMac.Foundation;
using MonoMac.WebKit;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
public class EmbedSampleMac : INativeDemoControl
{

2
samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs → samples/ControlCatalog.Desktop/NativeControls/Mac/MacHelper.cs

@ -3,7 +3,7 @@ using System;
using Avalonia.Controls.Platform;
using MonoMac.AppKit;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
internal class MacHelper
{

2
samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs → samples/ControlCatalog.Desktop/NativeControls/Win/EmbedSample.Win.cs

@ -6,7 +6,7 @@ using Avalonia.Platform;
using ControlCatalog.Pages;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
public class EmbedSampleWin : INativeDemoControl
{

2
samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs → samples/ControlCatalog.Desktop/NativeControls/Win/WinApi.cs

@ -1,7 +1,7 @@
using System;
using System.Runtime.InteropServices;
namespace ControlCatalog.NetCore;
namespace ControlCatalog.Desktop;
internal unsafe class WinApi
{

172
samples/ControlCatalog.Desktop/Program.cs

@ -1,38 +1,180 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Platform;
using ControlCatalog.NetCore;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Fonts.Inter;
using Avalonia.Headless;
using Avalonia.LinuxFramebuffer.Output;
using Avalonia.LogicalTree;
using Avalonia.Rendering.Composition;
using Avalonia.Threading;
using Avalonia.Vulkan;
using ControlCatalog.Pages;
namespace ControlCatalog
namespace ControlCatalog.Desktop
{
internal class Program
static class Program
{
private static bool s_useFramebuffer;
[STAThread]
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
static int Main(string[] args)
{
if (args.Contains("--fbdev"))
{
s_useFramebuffer = true;
}
if (args.Contains("--wait-for-attach"))
{
Console.WriteLine("Attach debugger and use 'Set next statement'");
while (true)
{
Thread.Sleep(100);
if (Debugger.IsAttached)
break;
}
}
var builder = BuildAvaloniaApp();
double GetScaling()
{
var idx = Array.IndexOf(args, "--scaling");
if (idx != 0 && args.Length > idx + 1 &&
double.TryParse(args[idx + 1], NumberStyles.Any, CultureInfo.InvariantCulture, out var scaling))
return scaling;
return 1;
}
if (s_useFramebuffer)
{
SilenceConsole();
return builder.StartLinuxFbDev(args, new FbDevOutputOptions()
{
Scaling = GetScaling()
});
}
else if (args.Contains("--vnc"))
{
return builder.StartWithHeadlessVncPlatform(null, 5901, args, ShutdownMode.OnMainWindowClose);
}
else if (args.Contains("--full-headless"))
{
return builder
.UseHeadless(new AvaloniaHeadlessPlatformOptions
{
UseHeadlessDrawing = true
})
.AfterSetup(_ =>
{
DispatcherTimer.RunOnce(async () =>
{
var window = ((IClassicDesktopStyleApplicationLifetime)Application.Current.ApplicationLifetime)
.MainWindow;
var tc = window.GetLogicalDescendants().OfType<TabControl>().First();
foreach (var page in tc.Items.Cast<TabItem>().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<object>().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);
}
/// <summary>
/// This method is needed for IDE previewer infrastructure
/// </summary>
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.LogToTrace()
.UsePlatformDetect()
.With(new X11PlatformOptions
{
EnableMultiTouch = true,
UseDBusMenu = true,
EnableIme = true,
})
.With(new VulkanOptions
{
VulkanInstanceCreationOptions = new ()
{
UseDebug = true
}
})
.With(new CompositionOptions()
{
UseRegionDirtyRectClipping = true
})
.UseSkia()
.WithInterFont()
.AfterSetup(builder =>
{
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
if (!s_useFramebuffer)
{
StartupScreenIndex = 1,
});
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
{
StartupScreenIndex = 1,
});
}
EmbedSample.Implementation = new EmbedSampleWin();
EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin()
: OperatingSystem.IsMacOS() ? new EmbedSampleMac()
: OperatingSystem.IsLinux() ? new EmbedSampleGtk()
: null;
})
.UseWin32()
.UseSkia();
.LogToTrace();
private static void ConfigureAssetAssembly(AppBuilder builder)
static void SilenceConsole()
{
AssetLoader.SetDefaultAssembly(typeof(App).Assembly);
new Thread(() =>
{
Console.CursorVisible = false;
while (true)
Console.ReadKey(true);
})
{ IsBackground = true }.Start();
}
}
}

2
samples/ControlCatalog.NetCore/Properties/launchSettings.json → samples/ControlCatalog.Desktop/Properties/launchSettings.json

@ -1,6 +1,6 @@
{
"profiles": {
"ControlCatalog.NetCore": {
"ControlCatalog.Desktop": {
"commandName": "Project"
},
"Dxgi": {

0
samples/ControlCatalog.NetCore/app.manifest → samples/ControlCatalog.Desktop/app.manifest

2
samples/ControlCatalog.MacCatalyst/ControlCatalog.MacCatalyst.csproj

@ -5,7 +5,7 @@
<ProvisioningType>manual</ProvisioningType>
<TargetFramework>$(AvsCurrentMacCatalystTargetFramework)</TargetFramework>
<!-- Used to support Desktop Mode Idiom, min supported version is 13.1, which supports iPad scaling. -->
<SupportedOSPlatformVersion>14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>

41
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -1,41 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\src\Avalonia.X11\NativeDialogs\Gtk.cs" Link="NativeControls\Gtk\Gtk.cs" />
<Compile Include="..\..\src\Avalonia.X11\Interop\Glib.cs" Link="NativeControls\Gtk\Glib.cs" />
<Compile Include="..\..\src\Avalonia.Base\Platform\Interop\Utf8Buffer.cs" Link="NativeControls\Utf8Buffer.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="NativeControls\Gtk\nodes.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.Vnc\Avalonia.Headless.Vnc.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<!-- For native controls test -->
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
</ItemGroup>
<PropertyGroup>
<!-- For Microsoft.CodeAnalysis -->
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
</Project>

180
samples/ControlCatalog.NetCore/Program.cs

@ -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<TabControl>().First();
foreach (var page in tc.Items.Cast<TabItem>().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<object>().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);
}
/// <summary>
/// This method is needed for IDE previewer infrastructure
/// </summary>
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.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();
}
}
}

2
samples/ControlCatalog/ControlCatalog.csproj

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(AvsCurrentTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(AvsCurrentTargetFramework)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<IncludeAvaloniaGenerators>true</IncludeAvaloniaGenerators>

6
samples/ControlCatalog/Pages/ClipboardPage.xaml

@ -6,6 +6,8 @@
<Button Click="CopyText" Content="Copy text to clipboard" />
<Button Click="PasteText" Content="Paste text from clipboard" />
<Button Click="CopyImage" Content="Copy image to clipboard" />
<Button Click="PasteImage" Content="Paste image from clipboard" />
<Button Click="CopyFiles" Content="Copy files to clipboard" />
<Button Click="PasteFiles" Content="Paste files from clipboard" />
<Button Click="CopyBinaryData" Content="Copy bytes to clipboard" />
@ -20,5 +22,9 @@
MinHeight="100"
AcceptsReturn="True"
Watermark="Text to copy of file names per line" />
<Viewbox Width="420" Height="360">
<Image x:Name="ClipboardImage"
/>
</Viewbox>
</StackPanel>
</UserControl>

31
samples/ControlCatalog/Pages/ClipboardPage.xaml.cs

@ -8,6 +8,8 @@ using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
@ -24,11 +26,19 @@ namespace ControlCatalog.Pages
private readonly DispatcherTimer _clipboardLastDataObjectChecker;
private DataTransfer? _storedDataTransfer;
private bool _checkingClipboardDataTransfer;
private Bitmap _defaultImage;
public ClipboardPage()
{
InitializeComponent();
_clipboardLastDataObjectChecker =
new DispatcherTimer(TimeSpan.FromSeconds(0.5), default, CheckLastDataObject);
using var asset = AssetLoader.Open(new Uri("avares://ControlCatalog/Assets/image1.jpg"));
_defaultImage = new Bitmap(asset);
ClipboardImage.Source = _defaultImage;
}
private async void CopyText(object? sender, RoutedEventArgs args)
@ -37,6 +47,12 @@ namespace ControlCatalog.Pages
await clipboard.SetTextAsync(ClipboardContent.Text ?? string.Empty);
}
private async void CopyImage(object? sender, RoutedEventArgs args)
{
if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
await clipboard.SetValueAsync(DataFormat.Bitmap, _defaultImage);
}
private async void PasteText(object? sender, RoutedEventArgs args)
{
if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
@ -45,6 +61,20 @@ namespace ControlCatalog.Pages
}
}
private async void PasteImage(object? sender, RoutedEventArgs args)
{
if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
{
using var data = await clipboard.TryGetDataAsync();
Bitmap? source = null;
if (data != null)
{
source = await data!.TryGetValueAsync(DataFormat.Bitmap);
}
ClipboardImage.Source = source;
}
}
private async void CopyFiles(object? sender, RoutedEventArgs args)
{
if (TopLevel.GetTopLevel(this)?.Clipboard is { } clipboard)
@ -154,7 +184,6 @@ namespace ControlCatalog.Pages
base.OnDetachedFromVisualTree(e);
}
private bool _checkingClipboardDataTransfer;
private async void CheckLastDataObject(object? sender, EventArgs e)
{
if (_checkingClipboardDataTransfer)

6
samples/ControlCatalog/Pages/DragAndDropPage.xaml

@ -25,6 +25,10 @@
Classes="draggable">
<TextBlock Name="DragStateFiles" TextWrapping="Wrap">Drag Me (files)</TextBlock>
</Border>
<Border Name="DragMeBitmap"
Classes="draggable">
<TextBlock Name="DragStateBitmap" TextWrapping="Wrap">Drag Me (bitmap)</TextBlock>
</Border>
<Border Name="DragMeCustom"
Classes="draggable">
<TextBlock Name="DragStateCustom" TextWrapping="Wrap">Drag Me (custom)</TextBlock>
@ -51,6 +55,6 @@
</StackPanel>
</WrapPanel>
<TextBlock x:Name="DropState" TextWrapping="Wrap" />
<ContentControl x:Name="DropState" TextBlock.TextWrapping="Wrap" />
</StackPanel>
</UserControl>

26
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -4,6 +4,11 @@ using System.Reflection;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Platform.Storage;
namespace ControlCatalog.Pages
@ -41,6 +46,11 @@ namespace ControlCatalog.Pages
}
},
DragDropEffects.Copy);
SetupDnd(
"Bitmap",
d => d.Add(DataTransferItem.Create(DataFormat.Bitmap, new Bitmap(AssetLoader.Open(new Uri("avares://ControlCatalog/Assets/image1.jpg"))))),
DragDropEffects.Copy);
}
private void SetupDnd(string suffix, Action<DataTransfer> factory, DragDropEffects effects) =>
@ -98,6 +108,7 @@ namespace ControlCatalog.Pages
// Only allow if the dragged data contains text or filenames.
if (!e.DataTransfer.Contains(DataFormat.Text)
&& !e.DataTransfer.Contains(DataFormat.File)
&& !e.DataTransfer.Contains(DataFormat.Bitmap)
&& !e.DataTransfer.Contains(_customFormat))
e.DragEffects = DragDropEffects.None;
}
@ -115,7 +126,7 @@ namespace ControlCatalog.Pages
if (e.DataTransfer.Contains(DataFormat.Text))
{
DropState.Text = e.DataTransfer.TryGetText();
DropState.Content = e.DataTransfer.TryGetText();
}
else if (e.DataTransfer.Contains(DataFormat.File))
{
@ -139,12 +150,19 @@ namespace ControlCatalog.Pages
contentStr += $"Folder {item.Name}: items {childrenCount}{Environment.NewLine}{Environment.NewLine}";
}
}
DropState.Text = contentStr;
DropState.Content = contentStr;
}
else if (e.DataTransfer.Contains(DataFormat.Bitmap))
{
var bitmap = e.DataTransfer.TryGetValue(DataFormat.Bitmap);
DropState.Content = new Image
{
Source = bitmap, Width = 400, Height = 300, Stretch = Stretch.Uniform
};
}
else if (e.DataTransfer.Contains(_customFormat))
{
DropState.Text = "Custom: " + e.DataTransfer.TryGetValue(_customFormat);
DropState.Content = "Custom: " + e.DataTransfer.TryGetValue(_customFormat);
}
}

4
samples/Directory.Build.props

@ -2,9 +2,9 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\netstandard2.0\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Designer.HostApp\bin\Debug\$(AvsCurrentTargetFramework)\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<LangVersion>12</LangVersion>
<LangVersion>14.0</LangVersion>
<NoWarn>$(NoWarn);CS8002</NoWarn> <!-- ignore signing warnings for samples -->
</PropertyGroup>

4
samples/Generators.Sandbox/App.xaml.cs

@ -12,9 +12,9 @@ public class App : Application
{
var view = new Views.SignUpView
{
ViewModel = new SignUpViewModel()
DataContext = new SignUpViewModel()
};
view.Show();
base.OnFrameworkInitializationCompleted();
}
}
}

37
samples/Generators.Sandbox/Controls/SignUpView.xaml

@ -1,45 +1,58 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Generators.Sandbox.Controls"
x:Class="Generators.Sandbox.Controls.SignUpView">
<StackPanel>
xmlns:vm="clr-namespace:Generators.Sandbox.ViewModels"
x:Class="Generators.Sandbox.Controls.SignUpView"
x:DataType="vm:SignUpViewModel">
<UserControl.Styles>
<Style Selector="DataValidationErrors">
<Setter Property="ErrorTemplate">
<Setter.Value>
<DataTemplate />
</Setter.Value>
</Setter>
</Style>
</UserControl.Styles>
<StackPanel>
<controls:CustomTextBox Margin="0 10 0 0"
x:Name="UserNameTextBox"
Text="{Binding UserName}"
Watermark="Please, enter user name..."
UseFloatingWatermark="True" />
<TextBlock x:Name="UserNameValidation"
<TextBlock x:Name="UserNameValidation"
Text="{Binding UserNameValidation}"
Foreground="Green"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="PasswordTextBox"
Text="{Binding Password}"
Watermark="Please, enter your password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="PasswordValidation"
<TextBlock x:Name="PasswordValidation"
Text="{Binding PasswordValidation}"
Foreground="Red"
FontSize="12" />
<TextBox Margin="0 10 0 0"
x:Name="ConfirmPasswordTextBox"
Text="{Binding ConfirmPassword}"
Watermark="Please, confirm the password..."
UseFloatingWatermark="True"
PasswordChar="*" />
<TextBlock x:Name="ConfirmPasswordValidation"
Text="{Binding ConfirmPasswordValidation}"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
<TextBlock>
<TextBlock.Inlines>
<InlineCollection>
<Run x:Name="SignUpButtonDescription" />
</InlineCollection>
</TextBlock.Inlines>
</TextBlock>
<TextBlock Text="Press the button below to sign up." />
<Button Margin="0 10 0 5"
Content="Sign up"
Command="{Binding SignUp}"
x:Name="SignUpButton" />
<TextBlock x:Name="CompoundValidation"
TextWrapping="Wrap"
Foreground="Red"
FontSize="12" />
FontSize="12"
Text="{Binding CompoundValidation}" />
</StackPanel>
</UserControl>

39
samples/Generators.Sandbox/Controls/SignUpView.xaml.cs

@ -1,10 +1,4 @@
using System;
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using Generators.Sandbox.ViewModels;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Formatters;
using Avalonia.Controls;
namespace Generators.Sandbox.Controls;
@ -14,41 +8,12 @@ namespace Generators.Sandbox.Controls;
/// references are living in a separate partial class file. See also:
/// https://devblogs.microsoft.com/dotnet/new-c-source-generator-samples/
/// </summary>
public partial class SignUpView : ReactiveUserControl<SignUpViewModel>
public partial class SignUpView : UserControl
{
public SignUpView()
{
// The InitializeComponent method is also generated automatically
// and lives in the autogenerated part of the partial class.
InitializeComponent();
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, x => x.UserName, x => x.UserNameTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.Password, x => x.PasswordTextBox.Text)
.DisposeWith(disposables);
this.Bind(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordTextBox.Text)
.DisposeWith(disposables);
this.BindCommand(ViewModel, x => x.SignUp, x => x.SignUpButton)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.UserName, x => x.UserNameValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
.DisposeWith(disposables);
this.BindValidation(ViewModel, x => x.ConfirmPassword, x => x.ConfirmPasswordValidation.Text)
.DisposeWith(disposables);
var newLineFormatter = new SingleLineFormatter(Environment.NewLine);
this.BindValidation(ViewModel, x => x.CompoundValidation.Text, newLineFormatter)
.DisposeWith(disposables);
// The references to text boxes below are also auto generated.
// Use Ctrl+Click in order to view the generated sources.
UserNameTextBox.Text = "Joseph!";
PasswordTextBox.Text = "1234";
ConfirmPasswordTextBox.Text = "1234";
SignUpButtonDescription.Text = "Press the button below to sign up.";
});
}
}

14
samples/Generators.Sandbox/Generators.Sandbox.csproj

@ -1,4 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
@ -6,23 +7,24 @@
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="**\*.xaml"/>
<AvaloniaXaml Include="**\*.xaml"/>
<!-- Note this AdditionalFiles directive. -->
<AdditionalFiles Include="**\*.xaml" SourceItemGroup="AvaloniaXaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ReactiveUI.Validation" Version="3.0.22"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj"/>
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets"/>
<Import Project="..\..\build\SourceGenerators.props"/>
<Import Project="..\..\build\NullableEnable.props" />
</Project>

2
samples/Generators.Sandbox/Program.cs

@ -1,5 +1,4 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace Generators.Sandbox;
@ -9,7 +8,6 @@ internal static class Program
private static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect()
.LogToTrace();
}

102
samples/Generators.Sandbox/ViewModels/SignUpViewModel.cs

@ -1,70 +1,76 @@
using System.Reactive;
using ReactiveUI;
using ReactiveUI.Validation.Extensions;
using ReactiveUI.Validation.Helpers;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Generators.Sandbox.ViewModels;
public class SignUpViewModel : ReactiveValidationObject
public class SignUpViewModel : ObservableValidator
{
private string _userName = string.Empty;
private string _password = string.Empty;
private string _confirmPassword = string.Empty;
public SignUpViewModel()
{
this.ValidationRule(
vm => vm.UserName,
name => !string.IsNullOrWhiteSpace(name),
"UserName is required.");
this.ValidationRule(
vm => vm.Password,
password => !string.IsNullOrWhiteSpace(password),
"Password is required.");
UserName = "Joseph!";
Password = "1234";
ConfirmPassword = "1234";
SignUp = new RelayCommand(() => { }, () => !HasErrors);
this.ValidationRule(
vm => vm.Password,
password => password?.Length > 2,
password => $"Password should be longer, current length: {password.Length}");
ErrorsChanged += OnErrorsChanged;
}
this.ValidationRule(
vm => vm.ConfirmPassword,
confirmation => !string.IsNullOrWhiteSpace(confirmation),
"Confirm password field is required.");
public RelayCommand SignUp { get; }
var passwordsObservable =
this.WhenAnyValue(
x => x.Password,
x => x.ConfirmPassword,
(password, confirmation) =>
password == confirmation);
[Required]
public string? UserName {
get;
set => SetProperty(ref field, value, validate: true);
}
this.ValidationRule(
vm => vm.ConfirmPassword,
passwordsObservable,
"Passwords must match.");
public string? UserNameValidation
=> GetValidationMessage(nameof(UserName));
SignUp = ReactiveCommand.Create(() => {}, this.IsValid());
[Required]
[MinLength(2)]
public string? Password
{
get;
set
{
if (SetProperty(ref field, value, validate: true))
ValidateProperty(ConfirmPassword, nameof(ConfirmPassword));
}
}
public ReactiveCommand<Unit, Unit> SignUp { get; }
public string? PasswordValidation
=> GetValidationMessage(nameof(Password));
public string UserName
[Required]
[Compare(nameof(Password))]
public string? ConfirmPassword
{
get => _userName;
set => this.RaiseAndSetIfChanged(ref _userName, value);
get;
set => SetProperty(ref field, value, validate: true);
}
public string Password
public string? ConfirmPasswordValidation
=> GetValidationMessage(nameof(ConfirmPassword));
public string? CompoundValidation
=> GetValidationMessage(null);
private void OnErrorsChanged(object? sender, DataErrorsChangedEventArgs e)
{
get => _password;
set => this.RaiseAndSetIfChanged(ref _password, value);
if (e.PropertyName is not null)
OnPropertyChanged(e.PropertyName + "Validation");
OnPropertyChanged(CompoundValidation);
SignUp.NotifyCanExecuteChanged();
}
public string ConfirmPassword
private string? GetValidationMessage(string? propertyName)
{
get => _confirmPassword;
set => this.RaiseAndSetIfChanged(ref _confirmPassword, value);
var message = string.Join(Environment.NewLine, GetErrors(propertyName).Select(v => v.ErrorMessage));
return string.IsNullOrEmpty(message) ? null : message;
}
}
}

15
samples/Generators.Sandbox/Views/SignUpView.xaml.cs

@ -1,7 +1,4 @@
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using Generators.Sandbox.ViewModels;
using ReactiveUI;
using Avalonia.Controls;
namespace Generators.Sandbox.Views;
@ -11,18 +8,12 @@ namespace Generators.Sandbox.Views;
/// references are living in a separate partial class file. See also:
/// https://devblogs.microsoft.com/dotnet/new-c-source-generator-samples/
/// </summary>
public partial class SignUpView : ReactiveWindow<SignUpViewModel>
public partial class SignUpView : Window
{
public SignUpView()
{
// The InitializeComponent method is also generated automatically
// and lives in the autogenerated part of the partial class.
InitializeComponent();
this.WhenActivated(disposables =>
{
this.WhenAnyValue(view => view.ViewModel)
.BindTo(this, view => view.SignUpControl.ViewModel)
.DisposeWith(disposables);
});
}
}
}

4
samples/GpuInterop/App.axaml.cs

@ -6,6 +6,8 @@ namespace GpuInterop
{
public class App : Application
{
public DemoType DemoType { get; set; }
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
@ -15,7 +17,7 @@ namespace GpuInterop
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
{
desktopLifetime.MainWindow = new MainWindow();
desktopLifetime.MainWindow = new MainWindow(DemoType);
}
}
}

187
samples/GpuInterop/D3DDemo/D3D11DemoControl.cs

@ -5,57 +5,79 @@ using System.Numerics;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering.Composition;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Buffer = SharpDX.Direct3D11.Buffer;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Matrix = SharpDX.Matrix;
using D3DDevice = SharpDX.Direct3D11.Device;
using FeatureLevel = SharpDX.Direct3D.FeatureLevel;
using Vector3 = SharpDX.Vector3;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
public class D3D11DemoControl : DrawingSurfaceDemoBase
{
private D3DDevice? _device;
private ComPtr<ID3D11Device> _device;
private D3D11Swapchain? _swapchain;
private DeviceContext? _context;
private Matrix _view;
private ComPtr<ID3D11DeviceContext> _context;
private Matrix4x4 _view;
private PixelSize _lastSize;
private Texture2D? _depthBuffer;
private DepthStencilView? _depthView;
private Matrix _proj;
private Buffer? _constantBuffer;
private ComPtr<ID3D11Texture2D> _depthBuffer;
private ComPtr<ID3D11DepthStencilView> _depthView;
private Matrix4x4 _proj;
private ComPtr<ID3D11Buffer> _constantBuffer;
private readonly Stopwatch _st = Stopwatch.StartNew();
protected override (bool success, string info) InitializeGraphicsResources(Compositor compositor,
protected override unsafe (bool success, string info) InitializeGraphicsResources(Compositor compositor,
CompositionDrawingSurface surface, ICompositionGpuInterop interop)
{
if (interop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes
.D3D11TextureGlobalSharedHandle) != true)
return (false, "DXGI shared handle import is not supported by the current graphics backend");
var factory = new DxgiFactory1();
using var adapter = factory.GetAdapter1(0);
_device = new D3DDevice(adapter, DeviceCreationFlags.None, new[]
using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
using var factory = dxgi.CreateDXGIFactory1<IDXGIFactory1>();
using ComPtr<IDXGIAdapter> adapter = default;
ThrowHResult(factory.EnumAdapters(0, adapter.GetAddressOf()));
const int featureLevelCount = 8;
var featureLevels = stackalloc D3DFeatureLevel[featureLevelCount]
{
FeatureLevel.Level_12_1,
FeatureLevel.Level_12_0,
FeatureLevel.Level_11_1,
FeatureLevel.Level_11_0,
FeatureLevel.Level_10_0,
FeatureLevel.Level_9_3,
FeatureLevel.Level_9_2,
FeatureLevel.Level_9_1,
});
_swapchain = new D3D11Swapchain(_device, interop, surface);
_context = _device.ImmediateContext;
D3DFeatureLevel.Level121,
D3DFeatureLevel.Level120,
D3DFeatureLevel.Level111,
D3DFeatureLevel.Level110,
D3DFeatureLevel.Level100,
D3DFeatureLevel.Level93,
D3DFeatureLevel.Level92,
D3DFeatureLevel.Level91
};
ComPtr<ID3D11Device> device = default;
ComPtr<ID3D11DeviceContext> context = default;
D3DFeatureLevel actualFeatureLevel;
ThrowHResult(d3d11.CreateDevice(
adapter,
D3DDriverType.Unknown,
IntPtr.Zero,
0u,
featureLevels,
featureLevelCount,
D3D11.SdkVersion,
device.GetAddressOf(),
&actualFeatureLevel,
context.GetAddressOf()));
_device = device;
_swapchain = new D3D11Swapchain(device, interop, surface);
_context = context;
_constantBuffer = D3DContent.CreateMesh(_device);
_view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
return (true, $"D3D11 ({_device.FeatureLevel}) {adapter.Description1.Description}");
_view = Matrix4x4.CreateLookAtLeftHanded(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
AdapterDesc adapterDesc;
ThrowHResult(adapter.GetDesc(&adapterDesc));
var description = PtrToString((IntPtr)adapterDesc.Description, NativeStringEncoding.LPWStr);
return (true, $"D3D11 ({actualFeatureLevel}) {description}");
}
protected override void FreeGraphicsResources()
@ -66,16 +88,16 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
_swapchain = null;
}
Utilities.Dispose(ref _depthView);
Utilities.Dispose(ref _depthBuffer);
Utilities.Dispose(ref _constantBuffer);
Utilities.Dispose(ref _context);
Utilities.Dispose(ref _device);
_depthView.Dispose();
_depthBuffer.Dispose();
_constantBuffer.Dispose();
_context.Dispose();
_device.Dispose();
}
protected override bool SupportsDisco => true;
protected override void RenderFrame(PixelSize pixelSize)
protected override unsafe void RenderFrame(PixelSize pixelSize)
{
if (pixelSize == default)
return;
@ -86,69 +108,70 @@ public class D3D11DemoControl : DrawingSurfaceDemoBase
}
using (_swapchain!.BeginDraw(pixelSize, out var renderView))
{
_device!.ImmediateContext.OutputMerger.SetTargets(_depthView, renderView);
var viewProj = Matrix.Multiply(_view, _proj);
var context = _device.ImmediateContext;
var renderViewHandle = renderView.Handle;
_context.OMSetRenderTargets(1, &renderViewHandle, _depthView);
var viewProj = _view * _proj;
var now = _st.Elapsed.TotalSeconds * 5;
var scaleX = (float)(1f + Disco * (Math.Sin(now) + 1) / 6);
var scaleY = (float)(1f + Disco * (Math.Cos(now) + 1) / 8);
var colorOff =(float) (Math.Sin(now) + 1) / 2 * Disco;
// Clear views
context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderView,
new RawColor4(1 - colorOff, colorOff, (float)0.5 + colorOff / 2, 1));
_context.ClearDepthStencilView(_depthView, (uint)ClearFlag.Depth, 1.0f, 0);
var color = new Vector4(1f - colorOff, colorOff, 0.5f + colorOff * 0.5f, 1.0f);
_context.ClearRenderTargetView(renderView, (float*)&color);
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
// Update WorldViewProj Matrix
var worldViewProj = Matrix.RotationX(Yaw) * Matrix.RotationY(Pitch)
* Matrix.RotationZ(Roll)
* Matrix.Scaling(new Vector3(scaleX, scaleY, 1))
* viewProj;
worldViewProj.Transpose();
context.UpdateSubresource(ref worldViewProj, _constantBuffer);
var ypr = Matrix4x4.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
var worldViewProj = ypr * Matrix4x4.CreateScale(new Vector3(scaleX, scaleY, 1)) * viewProj;
worldViewProj = Matrix4x4.Transpose(worldViewProj);
_context.UpdateSubresource(_constantBuffer, 0, null, &worldViewProj, 0, 0);
// Draw the cube
context.Draw(36, 0);
_context.Draw(36, 0);
_context!.Flush();
_context.Flush();
}
}
private void Resize(PixelSize size)
private unsafe void Resize(PixelSize size)
{
Utilities.Dispose(ref _depthBuffer);
_depthBuffer.Dispose();
if (_device is null)
if (_device.Handle == null)
return;
_depthBuffer = new Texture2D(_device,
new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = size.Width,
Height = size.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
Utilities.Dispose(ref _depthView);
_depthView = new DepthStencilView(_device, _depthBuffer);
ComPtr<ID3D11Texture2D> depthBuffer = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatD32FloatS8X24Uint,
ArraySize = 1,
MipLevels = 1,
Width = (uint)size.Width,
Height = (uint)size.Height,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.DepthStencil,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None
};
ThrowHResult(_device.CreateTexture2D(
&textureDesc,
(SubresourceData*)null,
depthBuffer.GetAddressOf()));
_depthBuffer = depthBuffer;
_depthView.Dispose();
ThrowHResult(_device.CreateDepthStencilView(_depthBuffer, null, ref _depthView));
// Setup targets and viewport for rendering
_device.ImmediateContext.Rasterizer.SetViewport(new Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f));
var viewport = new Viewport(0, 0, size.Width, size.Height, 0.0f, 1.0f);
_context.RSSetViewports(1, &viewport);
// Setup new projection matrix with correct aspect ratio
_proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, size.Width / (float) size.Height, 0.1f, 100.0f);
_proj = Matrix4x4.CreatePerspectiveFieldOfViewLeftHanded((float)Math.PI / 4.0f, size.Width / (float) size.Height, 0.1f, 100.0f);
}
}

80
samples/GpuInterop/D3DDemo/D3D11Swapchain.cs

@ -1,22 +1,22 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiResource = SharpDX.DXGI.Resource;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
{
private readonly D3DDevice _device;
private readonly ComPtr<ID3D11Device> _device;
public D3D11Swapchain(D3DDevice device, ICompositionGpuInterop interop, CompositionDrawingSurface target)
public D3D11Swapchain(ComPtr<ID3D11Device> device, ICompositionGpuInterop interop, CompositionDrawingSurface target)
: base(interop, target)
{
_device = device;
@ -24,7 +24,7 @@ class D3D11Swapchain : SwapchainBase<D3D11SwapchainImage>
protected override D3D11SwapchainImage CreateImage(PixelSize size) => new(_device, size, Interop, Target);
public IDisposable BeginDraw(PixelSize size, out RenderTargetView view)
public IDisposable BeginDraw(PixelSize size, out ComPtr<ID3D11RenderTargetView> view)
{
var rv = BeginDrawCore(size, out var image);
view = image.RenderTargetView;
@ -37,53 +37,67 @@ public class D3D11SwapchainImage : ISwapchainImage
public PixelSize Size { get; }
private readonly ICompositionGpuInterop _interop;
private readonly CompositionDrawingSurface _target;
private readonly Texture2D _texture;
private readonly KeyedMutex _mutex;
private ComPtr<ID3D11Texture2D> _texture;
private ComPtr<IDXGIKeyedMutex> _mutex;
private ComPtr<ID3D11RenderTargetView> _renderTargetView;
private readonly IntPtr _handle;
private PlatformGraphicsExternalImageProperties _properties;
private ICompositionImportedGpuImage? _imported;
public Task? LastPresent { get; private set; }
public RenderTargetView RenderTargetView { get; }
public ComPtr<ID3D11RenderTargetView> RenderTargetView => _renderTargetView;
public D3D11SwapchainImage(D3DDevice device, PixelSize size,
public unsafe D3D11SwapchainImage(
ComPtr<ID3D11Device> device,
PixelSize size,
ICompositionGpuInterop interop,
CompositionDrawingSurface target)
{
Size = size;
_interop = interop;
_target = target;
_texture = new Texture2D(device,
new Texture2DDescription
{
Format = Format.R8G8B8A8_UNorm,
Width = size.Width,
Height = size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
_mutex = _texture.QueryInterface<KeyedMutex>();
using (var res = _texture.QueryInterface<DxgiResource>())
_handle = res.SharedHandle;
ComPtr<ID3D11Texture2D> texture = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatR8G8B8A8Unorm,
Width = (uint)size.Width,
Height = (uint)size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)(BindFlag.RenderTarget | BindFlag.ShaderResource),
CPUAccessFlags = 0,
MiscFlags = (uint)ResourceMiscFlag.SharedKeyedmutex
};
ThrowHResult(device.CreateTexture2D(&textureDesc, (SubresourceData*)null, texture.GetAddressOf()));
_texture = texture;
_mutex = _texture.QueryInterface<IDXGIKeyedMutex>();
using (var res = _texture.QueryInterface<IDXGIResource>())
{
void* handle = null;
ThrowHResult(res.GetSharedHandle(ref handle));
_handle = (IntPtr)handle;
}
_properties = new PlatformGraphicsExternalImageProperties
{
Width = size.Width, Height = size.Height, Format = PlatformGraphicsExternalImageFormat.B8G8R8A8UNorm
};
RenderTargetView = new RenderTargetView(device, _texture);
ThrowHResult(device.CreateRenderTargetView(_texture, null, ref _renderTargetView));
}
public void BeginDraw()
{
_mutex.Acquire(0, int.MaxValue);
_mutex.AcquireSync(0, int.MaxValue);
}
public void Present()
{
_mutex.Release(1);
_mutex.ReleaseSync(1);
_imported ??= _interop.ImportImage(
new PlatformHandle(_handle, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureGlobalSharedHandle),
_properties);
@ -103,8 +117,8 @@ public class D3D11SwapchainImage : ISwapchainImage
// Ignore
}
RenderTargetView.Dispose();
_renderTargetView.Dispose();
_mutex.Dispose();
_texture.Dispose();
}
}
}

224
samples/GpuInterop/D3DDemo/D3DContent.cs

@ -1,110 +1,158 @@
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D;
using System;
using System.Linq;
using System.Threading.Tasks;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using Buffer = SharpDX.Direct3D11.Buffer;
using DeviceContext = SharpDX.Direct2D1.DeviceContext;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Matrix = SharpDX.Matrix;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiResource = SharpDX.DXGI.Resource;
using FeatureLevel = SharpDX.Direct3D.FeatureLevel;
using InputElement = SharpDX.Direct3D11.InputElement;
using System.Numerics;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D.Compilers;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.D3DDemo;
public class D3DContent
public static class D3DContent
{
private static D3DCompiler s_compiler = D3DCompiler.GetApi();
public static Buffer CreateMesh(D3DDevice device)
public static unsafe ComPtr<ID3D11Buffer> CreateMesh(ComPtr<ID3D11Device> device)
{
// Compile Vertex and Pixel shaders
var vertexShaderByteCode = ShaderBytecode.CompileFromFile("D3DDemo\\MiniCube.fx", "VS", "vs_4_0");
var vertexShader = new VertexShader(device, vertexShaderByteCode);
using var vertexShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "VS", "vs_4_0");
using ComPtr<ID3D11VertexShader> vertexShader = default;
ThrowHResult(device.CreateVertexShader(
vertexShaderByteCode.GetBufferPointer(),
vertexShaderByteCode.GetBufferSize(),
(ID3D11ClassLinkage*)null,
vertexShader.GetAddressOf()));
var pixelShaderByteCode = ShaderBytecode.CompileFromFile("D3DDemo\\MiniCube.fx", "PS", "ps_4_0");
var pixelShader = new PixelShader(device, pixelShaderByteCode);
using var pixelShaderByteCode = CompileShader("D3DDemo\\MiniCube.fx", "PS", "ps_4_0");
using ComPtr<ID3D11PixelShader> pixelShader = default;
ThrowHResult(device.CreatePixelShader(
pixelShaderByteCode.GetBufferPointer(),
pixelShaderByteCode.GetBufferSize(),
(ID3D11ClassLinkage*)null,
pixelShader.GetAddressOf()));
var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
using ComPtr<ID3D10Blob> vertexShaderSignature = default;
ThrowHResult(s_compiler.GetInputSignatureBlob(
vertexShaderByteCode.GetBufferPointer(),
vertexShaderByteCode.GetBufferSize(),
vertexShaderSignature.GetAddressOf()));
var inputElements = new[]
// Layout from VertexShader input signature
using ComPtr<ID3D11InputLayout> inputLayout = default;
var positionNamePtr = StringToPtr("POSITION", NativeStringEncoding.LPStr);
var colorNamePtr = StringToPtr("COLOR", NativeStringEncoding.LPStr);
try
{
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
};
const int inputCount = 2;
var inputs = stackalloc InputElementDesc[inputCount]
{
new InputElementDesc((byte*)positionNamePtr, 0, Format.FormatR32G32B32A32Float, 0, 0),
new InputElementDesc((byte*)colorNamePtr, 0, Format.FormatR32G32B32A32Float, 0, 16)
};
// Layout from VertexShader input signature
var layout = new InputLayout(
device,
signature,
inputElements);
ThrowHResult(device.CreateInputLayout(
inputs,
inputCount,
vertexShaderSignature.GetBufferPointer(),
vertexShaderSignature.GetBufferSize(),
inputLayout.GetAddressOf()));
}
finally
{
FreeString(positionNamePtr, NativeStringEncoding.LPStr);
FreeString(colorNamePtr, NativeStringEncoding.LPStr);
}
// Instantiate Vertex buffer from vertex data
using var vertices = Buffer.Create(
device,
BindFlags.VertexBuffer,
new[]
var vertices = new[]
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
};
using ComPtr<ID3D11Buffer> vertexBuffer = default;
fixed (Vector4* verticesPtr = vertices)
{
var vertexBufferDesc = new BufferDesc
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4(1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
});
ByteWidth = (uint)(sizeof(Vector4) * vertices.Length),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.VertexBuffer,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None,
StructureByteStride = 0
};
var subresourceData = new SubresourceData(verticesPtr);
ThrowHResult(device.CreateBuffer(&vertexBufferDesc, &subresourceData, vertexBuffer.GetAddressOf()));
}
// Create Constant Buffer
var constantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default,
BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
var context = device.ImmediateContext;
ComPtr<ID3D11Buffer> constantBuffer = default;
var constantBufferDesc = new BufferDesc
{
ByteWidth = (uint)sizeof(Matrix4x4),
Usage = Usage.Default,
BindFlags = (uint)BindFlag.ConstantBuffer,
CPUAccessFlags = (uint)CpuAccessFlag.None,
MiscFlags = (uint)ResourceMiscFlag.None,
StructureByteStride = 0
};
ThrowHResult(device.CreateBuffer(&constantBufferDesc, (SubresourceData*)null, constantBuffer.GetAddressOf()));
// Prepare All the stages
context.InputAssembler.InputLayout = layout;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
context.InputAssembler.SetVertexBuffers(0,
new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0));
context.VertexShader.SetConstantBuffer(0, constantBuffer);
context.VertexShader.Set(vertexShader);
context.PixelShader.Set(pixelShader);
using ComPtr<ID3D11DeviceContext> context = default;
device.GetImmediateContext(context.GetAddressOf());
context.IASetInputLayout(inputLayout);
context.IASetPrimitiveTopology(D3DPrimitiveTopology.D3D10PrimitiveTopologyTrianglelist);
var stride = (uint)(sizeof(Vector4) * 2);
var offset = 0u;
context.IASetVertexBuffers(0, 1, &vertexBuffer.Handle, &stride, &offset);
context.VSSetConstantBuffers(0, 1, &constantBuffer.Handle);
context.VSSetShader(vertexShader, (ID3D11ClassInstance**)null, 0);
context.PSSetShader(pixelShader, (ID3D11ClassInstance**)null, 0);
return constantBuffer;
}
private static unsafe ComPtr<ID3D10Blob> CompileShader(string fileName, string entryPoint, string profile)
{
ComPtr<ID3D10Blob> blob = default;
ThrowHResult(s_compiler.CompileFromFile(fileName, null, null, entryPoint, profile, 0u, 0u, blob.GetAddressOf(), null));
return blob;
}
}

7
samples/GpuInterop/DemoType.cs

@ -0,0 +1,7 @@
namespace GpuInterop;
public enum DemoType
{
Vulkan,
D3D11
}

14
samples/GpuInterop/GpuInterop.csproj

@ -7,7 +7,6 @@
<Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<UseD3DCompiler>true</UseD3DCompiler>
<UseSharpDXMathematics>true</UseSharpDXMathematics>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
@ -25,10 +24,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="Silk.NET.Direct3D11" Version="2.22.0" />
<PackageReference Include="Silk.NET.Direct3D.Compilers" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
<!-- Silk.NET 2.22 targets an obsolete System.Text.Json, update to avoid warnings. -->
<PackageReference Include="System.Text.Json" Version="10.0.0" />
</ItemGroup>
<ItemGroup>
@ -37,6 +39,7 @@
<ItemGroup>
<Compile Include="..\..\src\Avalonia.Base\Rendering\SwapchainBase.cs" />
<Compile Include="..\..\src\Avalonia.Base\Reactive\Disposable.cs" />
<None Remove="VulkanDemo\Assets\Shaders\frag.spirv" />
<EmbeddedResource Include="VulkanDemo\Assets\Shaders\frag.spirv" />
<None Remove="VulkanDemo\Assets\Shaders\vert.spirv" />
@ -47,5 +50,4 @@
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\SharpDX.props" />
</Project>

10
samples/GpuInterop/MainWindow.axaml

@ -1,13 +1,5 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:gpuInterop="clr-namespace:GpuInterop"
xmlns:d3DDemo="clr-namespace:GpuInterop.D3DDemo"
xmlns:vulkanDemo="clr-namespace:GpuInterop.VulkanDemo"
x:Class="GpuInterop.MainWindow">
<gpuInterop:GpuDemo>
<gpuInterop:GpuDemo.Demo>
<!--<d3DDemo:D3D11DemoControl/>-->
<vulkanDemo:VulkanDemoControl/>
</gpuInterop:GpuDemo.Demo>
</gpuInterop:GpuDemo>
</Window>

22
samples/GpuInterop/MainWindow.axaml.cs

@ -1,15 +1,35 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
using GpuInterop.D3DDemo;
using GpuInterop.VulkanDemo;
namespace GpuInterop
{
public class MainWindow : Window
{
public MainWindow()
public MainWindow() : this(DemoType.Vulkan)
{
}
public MainWindow(DemoType demoType)
{
InitializeComponent();
Title = demoType.ToString();
Content = new GpuDemo
{
Demo = demoType switch
{
DemoType.Vulkan => new VulkanDemoControl(),
DemoType.D3D11 => new D3D11DemoControl(),
var unknown => throw new InvalidOperationException($"Unknown demo type {unknown}")
}
};
this.AttachDevTools();
RendererDiagnostics.DebugOverlays = RendererDebugOverlays.Fps;
}

32
samples/GpuInterop/Program.cs

@ -1,29 +1,35 @@
global using System.Reactive.Disposables;
using System;
using Avalonia;
using Avalonia.Logging;
using Avalonia.Vulkan;
namespace GpuInterop
{
public class Program
public static class Program
{
static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
public static void Main(string[] args)
{
var demoType = OperatingSystem.IsWindows() && args.AsSpan().Contains("--d3d") ? DemoType.D3D11 : DemoType.Vulkan;
BuildAvaloniaAppCore(demoType).StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp() =>
AppBuilder.Configure<App>()
public static AppBuilder BuildAvaloniaApp() => BuildAvaloniaAppCore(DemoType.Vulkan);
private static AppBuilder BuildAvaloniaAppCore(DemoType demoType) =>
AppBuilder
.Configure(() => new App { DemoType = demoType })
.UsePlatformDetect()
.With(new Win32PlatformOptions
{
RenderingMode = new []
{
Win32RenderingMode.Vulkan
}
RenderingMode = [demoType == DemoType.D3D11 ? Win32RenderingMode.AngleEgl : Win32RenderingMode.Vulkan]
})
.With(new X11PlatformOptions
{
RenderingMode = [X11RenderingMode.Vulkan]
})
.With(new X11PlatformOptions(){RenderingMode =new[] { X11RenderingMode.Vulkan } })
.With(new VulkanOptions()
.With(new VulkanOptions
{
VulkanInstanceCreationOptions = new VulkanInstanceCreationOptions()
VulkanInstanceCreationOptions = new VulkanInstanceCreationOptions
{
UseDebug = true
}

12
samples/GpuInterop/Properties/launchSettings.json

@ -0,0 +1,12 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"GpuInterop (Vulkan)": {
"commandName": "Project",
},
"GpuInterop (Direct3D)": {
"commandName": "Project",
"commandLineArgs": "--d3d"
}
}
}

117
samples/GpuInterop/VulkanDemo/D3DMemoryHelper.cs

@ -1,54 +1,97 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Avalonia;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using D3DDevice = SharpDX.Direct3D11.Device;
using DxgiFactory1 = SharpDX.DXGI.Factory1;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using VulkanFormat = Silk.NET.Vulkan.Format;
using static Silk.NET.Core.Native.SilkMarshal;
namespace GpuInterop.VulkanDemo;
public class D3DMemoryHelper
{
public static D3DDevice CreateDeviceByLuid(Span<byte> luid)
private const int DxgiErrorNotFound = unchecked((int)0x887A0002);
public static unsafe ComPtr<ID3D11Device> CreateDeviceByLuid(Luid luid)
{
var factory = new DxgiFactory1();
var longLuid = MemoryMarshal.Cast<byte, long>(luid)[0];
for (var c = 0; c < factory.GetAdapterCount1(); c++)
using var dxgi = new DXGI(DXGI.CreateDefaultContext(["DXGI.dll"]));
using var d3d11 = new D3D11(D3D11.CreateDefaultContext(["d3d11.dll"]));
using var factory = dxgi.CreateDXGIFactory1<IDXGIFactory1>();
using var adapter = GetAdapterByLuid(factory, luid);
const int featureLevelCount = 8;
var featureLevels = stackalloc D3DFeatureLevel[featureLevelCount]
{
using var adapter = factory.GetAdapter1(c);
if (adapter.Description1.Luid != longLuid)
continue;
return new D3DDevice(adapter, DeviceCreationFlags.None,
new[]
{
FeatureLevel.Level_12_1, FeatureLevel.Level_12_0, FeatureLevel.Level_11_1,
FeatureLevel.Level_11_0, FeatureLevel.Level_10_0, FeatureLevel.Level_9_3,
FeatureLevel.Level_9_2, FeatureLevel.Level_9_1,
});
D3DFeatureLevel.Level121,
D3DFeatureLevel.Level120,
D3DFeatureLevel.Level111,
D3DFeatureLevel.Level110,
D3DFeatureLevel.Level100,
D3DFeatureLevel.Level93,
D3DFeatureLevel.Level92,
D3DFeatureLevel.Level91
};
ComPtr<ID3D11Device> device = default;
ComPtr<ID3D11DeviceContext> context = default;
D3DFeatureLevel actualFeatureLevel;
ThrowHResult(d3d11.CreateDevice(
adapter,
D3DDriverType.Unknown,
IntPtr.Zero,
0u,
featureLevels,
featureLevelCount,
D3D11.SdkVersion,
device.GetAddressOf(),
&actualFeatureLevel,
context.GetAddressOf()));
return device;
}
private static unsafe ComPtr<IDXGIAdapter> GetAdapterByLuid(ComPtr<IDXGIFactory1> factory, Luid luid)
{
var index = 0u;
ComPtr<IDXGIAdapter> adapter = default;
while (factory.EnumAdapters(index, adapter.GetAddressOf()) != DxgiErrorNotFound)
{
AdapterDesc adapterDesc;
if (adapter.GetDesc(&adapterDesc) == 0 & AreLuidsEqual(adapterDesc.AdapterLuid, luid))
return adapter;
adapter.Dispose();
++index;
}
throw new ArgumentException("Device with the corresponding LUID not found");
}
public static Texture2D CreateMemoryHandle(D3DDevice device, PixelSize size, Silk.NET.Vulkan.Format format)
public static unsafe ComPtr<ID3D11Texture2D> CreateMemoryHandle(ComPtr<ID3D11Device> device, PixelSize size, VulkanFormat format)
{
if (format != Silk.NET.Vulkan.Format.R8G8B8A8Unorm)
if (format != VulkanFormat.R8G8B8A8Unorm)
throw new ArgumentException("Not supported format");
return new Texture2D(device,
new Texture2DDescription
{
Format = Format.R8G8B8A8_UNorm,
Width = size.Width,
Height = size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDescription = new SampleDescription { Count = 1, Quality = 0 },
CpuAccessFlags = default,
OptionFlags = ResourceOptionFlags.SharedKeyedmutex|ResourceOptionFlags.SharedNthandle,
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource
});
ComPtr<ID3D11Texture2D> texture = default;
var textureDesc = new Texture2DDesc
{
Format = Format.FormatR8G8B8A8Unorm,
Width = (uint)size.Width,
Height = (uint)size.Height,
ArraySize = 1,
MipLevels = 1,
SampleDesc = new SampleDesc(1, 0),
Usage = Usage.Default,
BindFlags = (uint)(BindFlag.RenderTarget | BindFlag.ShaderResource),
CPUAccessFlags = 0,
MiscFlags = (uint)(ResourceMiscFlag.SharedKeyedmutex | ResourceMiscFlag.SharedNthandle)
};
ThrowHResult(device.CreateTexture2D(&textureDesc, (SubresourceData*)null, texture.GetAddressOf()));
return texture;
}
private static bool AreLuidsEqual(Luid x, Luid y)
=> x.Low == y.Low && x.High == y.High;
}

4
samples/GpuInterop/VulkanDemo/VulkanBufferHelper.cs

@ -25,7 +25,7 @@ static class VulkanBufferHelper
Usage = bufferUsageFlags,
SharingMode = SharingMode.Exclusive
};
api.CreateBuffer(device, bufferInfo, null, out buffer).ThrowOnError();
api.CreateBuffer(device, in bufferInfo, null, out buffer).ThrowOnError();
api.GetBufferMemoryRequirements(device, buffer, out var memoryRequirements);
@ -42,7 +42,7 @@ static class VulkanBufferHelper
MemoryPropertyFlags.HostVisibleBit)
};
api.AllocateMemory(device, memoryAllocateInfo, null, out memory).ThrowOnError();
api.AllocateMemory(device, in memoryAllocateInfo, null, out memory).ThrowOnError();
api.BindBufferMemory(device, buffer, memory, 0);
UpdateBufferMemory(vk, memory, initialData);
}

18
samples/GpuInterop/VulkanDemo/VulkanCommandBufferPool.cs

@ -28,7 +28,7 @@ namespace Avalonia.Vulkan
QueueFamilyIndex = queueFamilyIndex
};
_api.CreateCommandPool(_device, commandPoolCreateInfo, null, out _commandPool)
_api.CreateCommandPool(_device, in commandPoolCreateInfo, null, out _commandPool)
.ThrowOnError();
}
@ -53,7 +53,7 @@ namespace Avalonia.Vulkan
lock (_lock)
{
_api.AllocateCommandBuffers(_device, commandBufferAllocateInfo, out var commandBuffer);
_api.AllocateCommandBuffers(_device, in commandBufferAllocateInfo, out var commandBuffer);
return commandBuffer;
}
@ -111,15 +111,16 @@ namespace Avalonia.Vulkan
Flags = FenceCreateFlags.SignaledBit
};
api.CreateFence(device, fenceCreateInfo, null, out _fence);
api.CreateFence(device, in fenceCreateInfo, null, out _fence);
}
public unsafe void Dispose()
{
_api.WaitForFences(_device, 1, _fence, true, ulong.MaxValue);
_api.WaitForFences(_device, 1, in _fence, true, ulong.MaxValue);
lock (_commandBufferPool._lock)
{
_api.FreeCommandBuffers(_device, _commandBufferPool._commandPool, 1, InternalHandle);
var handle = InternalHandle;
_api.FreeCommandBuffers(_device, _commandBufferPool._commandPool, 1, in handle);
}
_api.DestroyFence(_device, _fence, null);
}
@ -136,7 +137,7 @@ namespace Avalonia.Vulkan
Flags = CommandBufferUsageFlags.OneTimeSubmitBit
};
_api.BeginCommandBuffer(InternalHandle, beginInfo);
_api.BeginCommandBuffer(InternalHandle, in beginInfo);
}
}
@ -212,9 +213,10 @@ namespace Avalonia.Vulkan
PSignalSemaphores = pSignalSemaphores,
};
_api.ResetFences(_device, 1, fence.Value);
var fenceValue = fence.Value;
_api.ResetFences(_device, 1, in fenceValue);
_api.QueueSubmit(_queue, 1, submitInfo, fence.Value);
_api.QueueSubmit(_queue, 1, in submitInfo, fenceValue);
}
}

43
samples/GpuInterop/VulkanDemo/VulkanContent.cs

@ -93,7 +93,7 @@ unsafe class VulkanContent : IDisposable
PCode = (uint*)ptr,
};
api.CreateShaderModule(device, shaderCreateInfo, null, out _vertShader);
api.CreateShaderModule(device, in shaderCreateInfo, null, out _vertShader);
}
fixed (byte* ptr = fragShaderData)
@ -105,7 +105,7 @@ unsafe class VulkanContent : IDisposable
PCode = (uint*)ptr,
};
api.CreateShaderModule(device, shaderCreateInfo, null, out _fragShader);
api.CreateShaderModule(device, in shaderCreateInfo, null, out _fragShader);
}
CreateBuffers();
@ -160,16 +160,16 @@ unsafe class VulkanContent : IDisposable
var commandBufferHandle = new CommandBuffer(commandBuffer.Handle);
api.CmdSetViewport(commandBufferHandle, 0, 1,
new Viewport()
{
Width = (float)image.Size.Width,
Height = (float)image.Size.Height,
MaxDepth = 1,
MinDepth = 0,
X = 0,
Y = 0
});
var viewport = new Viewport()
{
Width = (float)image.Size.Width,
Height = (float)image.Size.Height,
MaxDepth = 1,
MinDepth = 0,
X = 0,
Y = 0
};
api.CmdSetViewport(commandBufferHandle, 0, 1, in viewport);
var scissor = new Rect2D
{
@ -196,7 +196,7 @@ unsafe class VulkanContent : IDisposable
PClearValues = clearValue
};
api.CmdBeginRenderPass(commandBufferHandle, beginInfo, SubpassContents.Inline);
api.CmdBeginRenderPass(commandBufferHandle, in beginInfo, SubpassContents.Inline);
}
api.CmdBindPipeline(commandBufferHandle, PipelineBindPoint.Graphics, _pipeline);
@ -207,7 +207,8 @@ unsafe class VulkanContent : IDisposable
api.CmdPushConstants(commandBufferHandle, _pipelineLayout, ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, 0,
(uint)Marshal.SizeOf<VertexPushConstant>(), &vertexConstant);
api.CmdBindVertexBuffers(commandBufferHandle, 0, 1, _vertexBuffer, 0);
var offsets = 0ul;
api.CmdBindVertexBuffers(commandBufferHandle, 0, 1, in _vertexBuffer, in offsets);
api.CmdBindIndexBuffer(commandBufferHandle, _indexBuffer, 0, IndexType.Uint16);
api.CmdDrawIndexed(commandBufferHandle, (uint)_indices.Length, 1, 0, 0, 0);
@ -250,7 +251,7 @@ unsafe class VulkanContent : IDisposable
api.CmdBlitImage(commandBuffer.InternalHandle, _colorAttachment.InternalHandle,
ImageLayout.TransferSrcOptimal,
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, srcBlitRegion, Filter.Linear);
image.InternalHandle, ImageLayout.TransferDstOptimal, 1, in srcBlitRegion, Filter.Linear);
commandBuffer.Submit();
}
@ -341,7 +342,7 @@ unsafe class VulkanContent : IDisposable
var api = _context.Api;
var device = _context.Device;
api
.CreateImage(device, imageCreateInfo, null, out _depthImage).ThrowOnError();
.CreateImage(device, in imageCreateInfo, null, out _depthImage).ThrowOnError();
api.GetImageMemoryRequirements(device, _depthImage,
out var memoryRequirements);
@ -355,7 +356,7 @@ unsafe class VulkanContent : IDisposable
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
};
api.AllocateMemory(device, memoryAllocateInfo, null,
api.AllocateMemory(device, in memoryAllocateInfo, null,
out _depthImageMemory).ThrowOnError();
api.BindImageMemory(device, _depthImage, _depthImageMemory, 0);
@ -380,7 +381,7 @@ unsafe class VulkanContent : IDisposable
};
api
.CreateImageView(device, imageViewCreateInfo, null, out _depthImageView)
.CreateImageView(device, in imageViewCreateInfo, null, out _depthImageView)
.ThrowOnError();
}
@ -467,7 +468,7 @@ unsafe class VulkanContent : IDisposable
PDependencies = &subpassDependency
};
api.CreateRenderPass(device, renderPassCreateInfo, null, out _renderPass).ThrowOnError();
api.CreateRenderPass(device, in renderPassCreateInfo, null, out _renderPass).ThrowOnError();
// create framebuffer
@ -486,7 +487,7 @@ unsafe class VulkanContent : IDisposable
Layers = 1
};
api.CreateFramebuffer(device, framebufferCreateInfo, null, out _framebuffer).ThrowOnError();
api.CreateFramebuffer(device, in framebufferCreateInfo, null, out _framebuffer).ThrowOnError();
}
}
@ -691,7 +692,7 @@ unsafe class VulkanContent : IDisposable
PSetLayouts = &setLayout
};
api.CreatePipelineLayout(device, pipelineLayoutCreateInfo, null, out _pipelineLayout)
api.CreatePipelineLayout(device, in pipelineLayoutCreateInfo, null, out _pipelineLayout)
.ThrowOnError();
}

33
samples/GpuInterop/VulkanDemo/VulkanContext.cs

@ -9,13 +9,15 @@ using Avalonia.Vulkan;
using Silk.NET.Core;
using Silk.NET.Core.Contexts;
using Silk.NET.Core.Loader;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using D3DDevice = SharpDX.Direct3D11.Device;
#pragma warning disable CS0162 // Unreachable code detected
namespace GpuInterop.VulkanDemo;
@ -30,7 +32,7 @@ public unsafe class VulkanContext : IDisposable
public required VulkanCommandBufferPool Pool { get; init; }
public required GRContext? GrContext { get; init; }
public required DescriptorPool DescriptorPool { get; init; }
public required D3DDevice? D3DDevice { get; init; }
public required ComPtr<ID3D11Device> D3DDevice { get; init; }
public static (VulkanContext? result, string info) TryCreate(ICompositionGpuInterop gpuInterop)
{
@ -79,7 +81,8 @@ public unsafe class VulkanContext : IDisposable
enabledLayers.Clear();
using var pRequiredExtensions = new ByteStringList(enabledExtensions);
using var pEnabledLayers = new ByteStringList(enabledLayers);
api.CreateInstance(new InstanceCreateInfo
var instanceCreateInfo = new InstanceCreateInfo
{
SType = StructureType.InstanceCreateInfo,
PApplicationInfo = &applicationInfo,
@ -88,7 +91,9 @@ public unsafe class VulkanContext : IDisposable
PpEnabledLayerNames = pEnabledLayers,
EnabledLayerCount = pEnabledLayers.UCount,
Flags = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? InstanceCreateFlags.EnumeratePortabilityBitKhr : default
}, null, out var vkInstance).ThrowOnError();
};
api.CreateInstance(in instanceCreateInfo, null, out var vkInstance).ThrowOnError();
if (api.TryGetInstanceExtension(vkInstance, out ExtDebugUtils debugUtils))
@ -105,7 +110,7 @@ public unsafe class VulkanContext : IDisposable
PfnUserCallback = new PfnDebugUtilsMessengerCallbackEXT(LogCallback),
};
debugUtils.CreateDebugUtilsMessenger(vkInstance, debugCreateInfo, null, out _);
debugUtils.CreateDebugUtilsMessenger(vkInstance, in debugCreateInfo, null, out _);
}
var requireDeviceExtensions = new List<string>();
@ -273,13 +278,13 @@ public unsafe class VulkanContext : IDisposable
return (null, "Can't create Skia GrContext, device is likely broken");
}
D3DDevice? d3dDevice = null;
ComPtr<ID3D11Device> d3dDevice = null;
if (physicalDeviceIDProperties.DeviceLuidvalid &&
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
!gpuInterop.SupportedImageHandleTypes.Contains(KnownPlatformGraphicsExternalImageHandleTypes.VulkanOpaqueNtHandle)
)
d3dDevice = D3DMemoryHelper.CreateDeviceByLuid(
new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8));
MemoryMarshal.Read<Luid>(new Span<byte>(physicalDeviceIDProperties.DeviceLuid, 8)));
success = true;
return (new VulkanContext
{
@ -354,20 +359,14 @@ public unsafe class VulkanContext : IDisposable
private const string MacVulkanSdkGlobalPath = "/usr/local/lib/libvulkan.dylib";
class MacLibraryNameContainer : SearchPathContainer
{
public override string Windows64 { get; }
public override string Windows86 { get; }
public override string Linux { get; }
public override string MacOS { get; } = MacVulkanSdkGlobalPath;
}
private static Vk GetApi()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || !File.Exists(MacVulkanSdkGlobalPath))
return Vk.GetApi();
var ctx = new MultiNativeContext(new INativeContext[2]
{
Vk.CreateDefaultContext(new MacLibraryNameContainer().GetLibraryName()),
Vk.CreateDefaultContext([MacVulkanSdkGlobalPath]),
null!
});
var ret = new Vk(ctx);
@ -383,7 +382,7 @@ public unsafe class VulkanContext : IDisposable
public void Dispose()
{
D3DDevice?.Dispose();
D3DDevice.Dispose();
GrContext?.Dispose();
Pool.Dispose();
Api.DestroyDescriptorPool(Device, DescriptorPool, null);

49
samples/GpuInterop/VulkanDemo/VulkanImage.cs

@ -6,12 +6,15 @@ using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Platform;
using Avalonia.Vulkan;
using SharpDX.DXGI;
using Silk.NET.Core.Native;
using Silk.NET.Direct3D11;
using Silk.NET.DXGI;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR;
using SilkNetDemo;
using SkiaSharp;
using static Silk.NET.Core.Native.SilkMarshal;
using Device = Silk.NET.Vulkan.Device;
using Format = Silk.NET.Vulkan.Format;
@ -29,7 +32,7 @@ public unsafe class VulkanImage : IDisposable
private ImageUsageFlags _imageUsageFlags { get; }
private ImageView _imageView { get; set; }
private DeviceMemory _imageMemory { get; set; }
private readonly SharpDX.Direct3D11.Texture2D? _d3dTexture2D;
private ComPtr<ID3D11Texture2D> _d3dTexture2D;
internal Image InternalHandle { get; private set; }
internal Format Format { get; }
@ -111,7 +114,7 @@ public unsafe class VulkanImage : IDisposable
};
Api
.CreateImage(_device, imageCreateInfo, null, out var image).ThrowOnError();
.CreateImage(_device, in imageCreateInfo, null, out var image).ThrowOnError();
InternalHandle = image;
if (!exportable || !RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
@ -135,16 +138,16 @@ public unsafe class VulkanImage : IDisposable
ImportMemoryWin32HandleInfoKHR handleImport = default;
if (handleType == ExternalMemoryHandleTypeFlags.D3D11TextureBit && exportable)
{
var d3dDevice = vk.D3DDevice ?? throw new NotSupportedException("Vulkan D3DDevice wasn't created");
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(d3dDevice, size, Format);
using var dxgi = _d3dTexture2D.QueryInterface<SharpDX.DXGI.Resource1>();
if (vk.D3DDevice.Handle == null)
throw new NotSupportedException("Vulkan D3DDevice wasn't created");
_d3dTexture2D = D3DMemoryHelper.CreateMemoryHandle(vk.D3DDevice, size, Format);
handleImport = new ImportMemoryWin32HandleInfoKHR
{
PNext = &dedicatedAllocation,
SType = StructureType.ImportMemoryWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.D3D11TextureBit,
Handle = dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
Handle = CreateDxgiSharedHandle()
};
}
@ -160,7 +163,7 @@ public unsafe class VulkanImage : IDisposable
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.DeviceLocalBit)
};
Api.AllocateMemory(_device, memoryAllocateInfo, null,
Api.AllocateMemory(_device, in memoryAllocateInfo, null,
out var imageMemory).ThrowOnError();
_imageMemory = imageMemory;
@ -192,7 +195,7 @@ public unsafe class VulkanImage : IDisposable
};
Api
.CreateImageView(_device, imageViewCreateInfo, null, out var imageView)
.CreateImageView(_device, in imageViewCreateInfo, null, out var imageView)
.ThrowOnError();
_imageView = imageView;
@ -202,6 +205,20 @@ public unsafe class VulkanImage : IDisposable
TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.NoneKhr);
}
private IntPtr CreateDxgiSharedHandle()
{
using var dxgiResource = _d3dTexture2D.QueryInterface<IDXGIResource1>();
void* sharedHandle;
ThrowHResult(dxgiResource.CreateSharedHandle(
(SecurityAttributes*) null,
DXGI.SharedResourceRead | DXGI.SharedResourceWrite,
(char*)null,
&sharedHandle));
return (IntPtr)sharedHandle;
}
public int ExportFd()
{
if (!Api.TryGetDeviceExtension<KhrExternalMemoryFd>(_instance, _device, out var ext))
@ -212,7 +229,7 @@ public unsafe class VulkanImage : IDisposable
SType = StructureType.MemoryGetFDInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueFDBit
};
ext.GetMemoryF(_device, info, out var fd).ThrowOnError();
ext.GetMemoryF(_device, in info, out var fd).ThrowOnError();
return fd;
}
@ -226,7 +243,7 @@ public unsafe class VulkanImage : IDisposable
SType = StructureType.MemoryGetWin32HandleInfoKhr,
HandleType = ExternalMemoryHandleTypeFlags.OpaqueWin32Bit
};
ext.GetMemoryWin32Handle(_device, info, out var fd).ThrowOnError();
ext.GetMemoryWin32Handle(_device, in info, out var fd).ThrowOnError();
return fd;
}
@ -254,11 +271,10 @@ public unsafe class VulkanImage : IDisposable
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
if (_d3dTexture2D != null)
if (_d3dTexture2D.Handle != null)
{
using var dxgi = _d3dTexture2D!.QueryInterface<Resource1>();
return new PlatformHandle(
dxgi.CreateSharedHandle(null, SharedResourceFlags.Read | SharedResourceFlags.Write),
CreateDxgiSharedHandle(),
KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);
}
@ -275,7 +291,7 @@ public unsafe class VulkanImage : IDisposable
public ImageTiling Tiling => ImageTiling.Optimal;
public bool IsDirectXBacked => _d3dTexture2D != null;
public bool IsDirectXBacked => _d3dTexture2D.Handle != null;
internal void TransitionLayout(CommandBuffer commandBuffer,
ImageLayout fromLayout, AccessFlags fromAccessFlags,
@ -367,8 +383,7 @@ public unsafe class VulkanImage : IDisposable
}
};
using (var backendTexture = new GRBackendRenderTarget(_image.Size.Width, _image.Size.Height, 1,
imageInfo))
using (var backendTexture = new GRBackendRenderTarget(_image.Size.Width, _image.Size.Height, imageInfo))
using (var surface = SKSurface.Create(_vk.GrContext, backendTexture,
GRSurfaceOrigin.TopLeft,
SKColorType.Rgba8888, SKColorSpace.CreateSrgb()))

2
samples/GpuInterop/VulkanDemo/VulkanMemoryHelper.cs

@ -54,6 +54,6 @@ internal static class VulkanMemoryHelper
0,
null,
1,
barrier);
in barrier);
}
}

8
samples/GpuInterop/VulkanDemo/VulkanSemaphorePair.cs

@ -29,10 +29,10 @@ class VulkanSemaphorePair : IDisposable
PNext = exportable ? &semaphoreExportInfo : null
};
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
ImageAvailableSemaphore = semaphore;
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out semaphore).ThrowOnError();
RenderFinishedSemaphore = semaphore;
}
@ -47,7 +47,7 @@ class VulkanSemaphorePair : IDisposable
Semaphore = renderFinished ? RenderFinishedSemaphore : ImageAvailableSemaphore,
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueFDBit
};
ext.GetSemaphoreF(_resources.Device, info, out var fd).ThrowOnError();
ext.GetSemaphoreF(_resources.Device, in info, out var fd).ThrowOnError();
return fd;
}
@ -62,7 +62,7 @@ class VulkanSemaphorePair : IDisposable
Semaphore = renderFinished ? RenderFinishedSemaphore : ImageAvailableSemaphore,
HandleType = ExternalSemaphoreHandleTypeFlags.OpaqueWin32Bit
};
ext.GetSemaphoreWin32Handle(_resources.Device, info, out var fd).ThrowOnError();
ext.GetSemaphoreWin32Handle(_resources.Device, in info, out var fd).ThrowOnError();
return fd;
}

8
samples/GpuInterop/VulkanDemo/VulkanSwapchain.cs

@ -119,7 +119,7 @@ class VulkanSwapchainImage : ISwapchainImage
buffer.Submit();
}
else
buffer.Submit(new[] { _semaphorePair.ImageAvailableSemaphore },
buffer.Submit(new[] { _semaphorePair!.ImageAvailableSemaphore },
new[]
{
PipelineStageFlags.AllGraphicsBit
@ -160,7 +160,7 @@ class VulkanSwapchainImage : ISwapchainImage
}
}
else
buffer.Submit(null, null, new[] { _semaphorePair.RenderFinishedSemaphore });
buffer.Submit(null, null, new[] { _semaphorePair!.RenderFinishedSemaphore });
if (_timelineSemaphore != null)
{
@ -168,9 +168,9 @@ class VulkanSwapchainImage : ISwapchainImage
}
else if (!_image.IsDirectXBacked)
{
_availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(false));
_availableSemaphore ??= _interop.ImportSemaphore(_semaphorePair!.Export(false));
_renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair.Export(true));
_renderCompletedSemaphore ??= _interop.ImportSemaphore(_semaphorePair!.Export(true));
}
_importedImage ??= _interop.ImportImage(_image.Export(),

2
samples/GpuInterop/VulkanDemo/VulkanTimelineSemaphore.cs

@ -32,7 +32,7 @@ class VulkanTimelineSemaphore : IDisposable
SType = StructureType.SemaphoreCreateInfo,
PNext = &semaphoreTypeInfo,
};
resources.Api.CreateSemaphore(resources.Device, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
resources.Api.CreateSemaphore(resources.Device, in semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
Handle = semaphore;
}

7
samples/IntegrationTestApp/MainWindow.axaml

@ -37,14 +37,17 @@
DisplayMemberBinding="{Binding Name}"
ItemsSource="{Binding Pages}"
SelectedItem="{Binding SelectedPage}"
SelectionChanged="Pager_SelectionChanged">
SelectionChanged="Pager_SelectionChanged"
AutomationProperties.LandmarkType="Navigation">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Decorator Name="PagerContent"/>
<Decorator Name="PagerContent"
AutomationProperties.AccessibilityView="Control"
AutomationProperties.LandmarkType="Main"/>
</DockPanel>
</DockPanel>

2
samples/IntegrationTestApp/bundle.sh

@ -9,4 +9,4 @@ arch="arm64"
fi
dotnet restore -r osx-$arch
dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-$arch
dotnet msbuild -t:BundleApp -p:RuntimeIdentifier=osx-$arch -p:SelfContained=true

2
samples/MiniMvvm/MiniMvvm.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

8
samples/ReactiveUIDemo/App.axaml

@ -1,8 +0,0 @@
<Application
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ReactiveUIDemo.App">
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

37
samples/ReactiveUIDemo/App.axaml.cs

@ -1,37 +0,0 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using ReactiveUI;
using ReactiveUIDemo.ViewModels;
using ReactiveUIDemo.Views;
using Splat;
namespace ReactiveUIDemo
{
public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
Locator.CurrentMutable.Register(() => new FooView(), typeof(IViewFor<FooViewModel>));
Locator.CurrentMutable.Register(() => new BarView(), typeof(IViewFor<BarViewModel>));
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
}
}

19
samples/ReactiveUIDemo/MainWindow.axaml

@ -1,19 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="ReactiveUIDemo.MainWindow"
xmlns:vm="using:ReactiveUIDemo.ViewModels"
xmlns:rxui="using:Avalonia.ReactiveUI"
Title="AvaloniaUI ReactiveUI Demo"
x:DataType="vm:MainWindowViewModel">
<TabControl TabStripPlacement="Left">
<TabItem Header="RoutedViewHost">
<DockPanel DataContext="{Binding RoutedViewHost}">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="8">
<Button Command="{Binding ShowFoo}">Foo</Button>
<Button Command="{Binding ShowBar}">Bar</Button>
</StackPanel>
<rxui:RoutedViewHost Router="{Binding Router}"/>
</DockPanel>
</TabItem>
</TabControl>
</Window>

22
samples/ReactiveUIDemo/MainWindow.axaml.cs

@ -1,22 +0,0 @@
using ReactiveUIDemo.ViewModels;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ReactiveUIDemo
{
public class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MainWindowViewModel();
this.AttachDevTools();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

28
samples/ReactiveUIDemo/ReactiveUIDemo.csproj

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Fonts.Inter\Avalonia.Fonts.Inter.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Views\BarView.axaml.cs">
<DependentUpon>BarView.axaml</DependentUpon>
</Compile>
<Compile Update="Views\FooView.axaml.cs">
<DependentUpon>FooView.axaml</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\ReactiveUI.props" />
</Project>

11
samples/ReactiveUIDemo/ViewModels/BarViewModel.cs

@ -1,11 +0,0 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class BarViewModel : ReactiveObject, IRoutableViewModel
{
public BarViewModel(IScreen screen) => HostScreen = screen;
public string UrlPathSegment => "Bar";
public IScreen HostScreen { get; }
}
}

11
samples/ReactiveUIDemo/ViewModels/FooViewModel.cs

@ -1,11 +0,0 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class FooViewModel : ReactiveObject, IRoutableViewModel
{
public FooViewModel(IScreen screen) => HostScreen = screen;
public string UrlPathSegment => "Foo";
public IScreen HostScreen { get; }
}
}

9
samples/ReactiveUIDemo/ViewModels/MainWindowViewModel.cs

@ -1,9 +0,0 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class MainWindowViewModel : ReactiveObject
{
public RoutedViewHostPageViewModel RoutedViewHost { get; } = new();
}
}

21
samples/ReactiveUIDemo/ViewModels/RoutedViewHostPageViewModel.cs

@ -1,21 +0,0 @@
using ReactiveUI;
namespace ReactiveUIDemo.ViewModels
{
internal class RoutedViewHostPageViewModel : ReactiveObject, IScreen
{
public RoutedViewHostPageViewModel()
{
Foo = new(this);
Bar = new(this);
Router.Navigate.Execute(Foo);
}
public RoutingState Router { get; } = new();
public FooViewModel Foo { get; }
public BarViewModel Bar { get; }
public void ShowFoo() => Router.Navigate.Execute(Foo);
public void ShowBar() => Router.Navigate.Execute(Bar);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save