Browse Source

Merge branch 'master' into build-path-ps1

pull/4442/head
Max Katz 5 years ago
committed by GitHub
parent
commit
62ed62cf60
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      azure-pipelines.yml
  2. BIN
      build/Assets/Icon.png
  3. 8
      build/SharedVersion.props
  4. 4
      build/SourceLink.props
  5. 4
      build/XUnit.props
  6. BIN
      build/avalonia.snk
  7. 1
      dirs.proj
  8. 6
      native/Avalonia.Native/src/OSX/window.mm
  9. 3
      nukebuild/BuildTasksPatcher.cs
  10. 2
      nukebuild/_build.csproj
  11. 3
      packages/Avalonia/AvaloniaBuildTasks.targets
  12. 2
      readme.md
  13. 20
      samples/BindingDemo/App.xaml.cs
  14. 10
      samples/ControlCatalog.Desktop/Program.cs
  15. 3
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  16. 5
      samples/ControlCatalog.NetCore/Program.cs
  17. 10
      samples/Previewer/App.xaml.cs
  18. 15
      samples/Previewer/Program.cs
  19. 13
      samples/RenderDemo/App.xaml.cs
  20. 6
      samples/RenderDemo/Pages/GlyphRunPage.xaml
  21. 7
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  22. 2
      samples/Sandbox/Program.cs
  23. 8
      samples/VirtualizationDemo/App.xaml.cs
  24. 20
      samples/VirtualizationDemo/Program.cs
  25. 8
      samples/interop/Direct3DInteropSample/App.paml.cs
  26. 21
      samples/interop/Direct3DInteropSample/Program.cs
  27. 3
      samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
  28. 4
      src/Avalonia.Animation/Properties/AssemblyInfo.cs
  29. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  30. 14
      src/Avalonia.Base/Logging/TraceLogSink.cs
  31. 39
      src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs
  32. 10
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  33. 2
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  34. 8
      src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
  35. 26
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  36. 1
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  37. 13
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  38. 4
      src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
  39. 8
      src/Avalonia.Controls/ApiCompatBaseline.txt
  40. 13
      src/Avalonia.Controls/ContextMenu.cs
  41. 2
      src/Avalonia.Controls/ItemsControl.cs
  42. 19
      src/Avalonia.Controls/LoggingExtensions.cs
  43. 7
      src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
  44. 20
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  45. 1
      src/Avalonia.Controls/Primitives/IPopupHost.cs
  46. 34
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  47. 4
      src/Avalonia.Controls/Properties/AssemblyInfo.cs
  48. 44
      src/Avalonia.Controls/Shapes/Shape.cs
  49. 54
      src/Avalonia.Controls/SplitView.cs
  50. 23
      src/Avalonia.Controls/TextBlock.cs
  51. 2
      src/Avalonia.Controls/Window.cs
  52. 1
      src/Avalonia.Dialogs/ApiCompatBaseline.txt
  53. 4
      src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
  54. 5
      src/Avalonia.Input/KeyGesture.cs
  55. 20
      src/Avalonia.Input/MouseDevice.cs
  56. 2
      src/Avalonia.Layout/Properties/AssemblyInfo.cs
  57. 9
      src/Avalonia.Native/WindowImplBase.cs
  58. 10
      src/Avalonia.OpenGL/Angle/AngleEglInterface.cs
  59. 9
      src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs
  60. 6
      src/Avalonia.OpenGL/Egl/EglConsts.cs
  61. 1
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  62. 2
      src/Avalonia.Styling/Properties/AssemblyInfo.cs
  63. 8
      src/Avalonia.Themes.Default/SplitView.xaml
  64. 8
      src/Avalonia.Themes.Fluent/SplitView.xaml
  65. 4
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  66. 14
      src/Avalonia.Visuals/Media/Drawing.cs
  67. 4
      src/Avalonia.Visuals/Media/Geometry.cs
  68. 44
      src/Avalonia.Visuals/Media/GeometryDrawing.cs
  69. 1
      src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
  70. 2
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  71. 8
      src/Avalonia.Visuals/Properties/AssemblyInfo.cs
  72. 4
      src/Avalonia.Visuals/Rendering/RenderLayer.cs
  73. 7
      src/Avalonia.Visuals/Rendering/SceneGraph/ExperimentalAcrylicNode.cs
  74. 1
      src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
  75. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
  76. 84
      src/Avalonia.X11/XI2Manager.cs
  77. 43
      src/Avalonia.X11/XIStructs.cs
  78. 16
      src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs
  79. 31
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs
  80. 2
      src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
  81. 2
      src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs
  82. 8
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  83. 44
      src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
  84. 2
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs
  85. 2
      src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs
  86. 4
      src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs
  87. 9
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs
  88. 4
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs
  89. 3
      src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs
  90. 4
      src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs
  91. 6
      src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs
  92. 36
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  93. 1
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  94. 160
      src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs
  95. 4
      src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
  96. 2
      src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
  97. 3
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  98. 18
      src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs
  99. 143
      src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
  100. 96
      src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs

4
azure-pipelines.yml

@ -31,6 +31,8 @@ jobs:
condition: not(canceled())
- job: macOS
variables:
SolutionDir: '$(Build.SourcesDirectory)'
pool:
vmImage: 'macOS-10.14'
steps:
@ -97,6 +99,8 @@ jobs:
- job: Windows
pool:
vmImage: 'windows-2019'
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.401'

BIN
build/Assets/Icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

8
build/SharedVersion.props

@ -10,10 +10,16 @@
<NoWarn>CS1591</NoWarn>
<LangVersion>latest</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIconUrl>https://avatars2.githubusercontent.com/u/14075148?s=200</PackageIconUrl>
<PackageIcon>Icon.png</PackageIcon>
<PackageDescription>Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS.</PackageDescription>
<PackageTags>avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin</PackageTags>
<PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
<RepositoryType>git</RepositoryType>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>True</SignAssembly>
</PropertyGroup>
<ItemGroup Label="PackageIcon">
<None Include="$(MSBuildThisFileDirectory)/Assets/Icon.png" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>

4
build/SourceLink.props

@ -1,5 +1,5 @@
<Project>
<ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.0" PrivateAssets="All" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" />
</ItemGroup>
</Project>
</Project>

4
build/XUnit.props

@ -11,4 +11,8 @@
<PackageReference Include="Xunit.SkippableFact" Version="1.3.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
</ItemGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>True</SignAssembly>
</PropertyGroup>
</Project>

BIN
build/avalonia.snk

Binary file not shown.

1
dirs.proj

@ -21,6 +21,7 @@
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
<ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<ItemGroup>

6
native/Avalonia.Native/src/OSX/window.mm

@ -1338,6 +1338,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
}
_parent->BaseEvents->RunRenderPriorityJobs();
if (_parent == nullptr)
{
return;
}
_parent->BaseEvents->Paint();
}

3
nukebuild/BuildTasksPatcher.cs

@ -29,7 +29,8 @@ public class BuildTasksPatcher
InputAssemblies = new[]
{
temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0]
.FullyQualifiedName
.FullyQualifiedName,
typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName
},
SearchDirectories = new string[0],
OutputFile = output

2
nukebuild/_build.csproj

@ -16,7 +16,7 @@
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
<PackageReference Include="ILRepack.NETStandard" Version="2.0.4" />
<!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Pharmacist.Core" Version="1.8.1" />
</ItemGroup>

3
packages/Avalonia/AvaloniaBuildTasks.targets

@ -87,6 +87,9 @@
ProjectDirectory="$(MSBuildProjectDirectory)"
VerifyIl="$(AvaloniaXamlIlVerifyIl)"
ReportImportance="$(AvaloniaXamlReportImportance)"
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"

2
readme.md

@ -39,7 +39,7 @@ Examples of UIs built with Avalonia
## JetBrains Rider
If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen.
If you need to develop Avalonia app with JetBrains Rider you can use latest Rider [preview builds](https://www.jetbrains.com/rider/nextversion/).
## Bleeding Edge Builds

20
samples/BindingDemo/App.xaml.cs

@ -1,6 +1,5 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
@ -13,13 +12,20 @@ namespace BindingDemo
AvaloniaXamlLoader.Load(this);
}
private static void Main()
public override void OnFrameworkInitializationCompleted()
{
AppBuilder.Configure<App>()
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()
.LogToDebug()
.Start<MainWindow>();
}
.LogToTrace();
}
}

10
samples/ControlCatalog.Desktop/Program.cs

@ -10,19 +10,15 @@ namespace ControlCatalog
internal class Program
{
[STAThread]
static void Main(string[] args)
{
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again.
BuildAvaloniaApp().Start<MainWindow>();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
/// <summary>
/// This method is needed for IDE previewer infrastructure
/// </summary>
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.LogToDebug()
.LogToTrace()
.UsePlatformDetect()
.UseReactiveUI();

3
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -11,9 +11,8 @@
<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.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
</ItemGroup>

5
samples/ControlCatalog.NetCore/Program.cs

@ -7,12 +7,11 @@ using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Dialogs;
using Avalonia.Headless;
using Avalonia.LogicalTree;
using Avalonia.Skia;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using Avalonia.Dialogs;
namespace ControlCatalog.NetCore
{
@ -121,7 +120,7 @@ namespace ControlCatalog.NetCore
.UseSkia()
.UseReactiveUI()
.UseManagedSystemDialogs()
.LogToDebug();
.LogToTrace();
static void SilenceConsole()
{

10
samples/Previewer/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace Previewer
@ -9,6 +10,13 @@ namespace Previewer
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
}
}
}

15
samples/Previewer/Program.cs

@ -1,13 +1,14 @@
using System;
using Avalonia;
using Avalonia;
namespace Previewer
{
class Program
{
static void Main(string[] args)
{
AppBuilder.Configure<App>().UsePlatformDetect().Start<MainWindow>();
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect();
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
}
}

13
samples/RenderDemo/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
@ -11,9 +12,17 @@ namespace RenderDemo
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again.
static void Main(string[] args) => BuildAvaloniaApp().Start<MainWindow>();
static void Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
// App configuration, used by the entry point and previewer
static AppBuilder BuildAvaloniaApp()
@ -24,6 +33,6 @@ namespace RenderDemo
})
.UsePlatformDetect()
.UseReactiveUI()
.LogToDebug();
.LogToTrace();
}
}

6
samples/RenderDemo/Pages/GlyphRunPage.xaml

@ -6,9 +6,9 @@
x:Class="RenderDemo.Pages.GlyphRunPage">
<Border
Background="White">
<DrawingPresenter
x:Name="drawingPresenter"
<Image
x:Name="imageControl"
Stretch="None">
</DrawingPresenter>
</Image>
</Border>
</UserControl>

7
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -9,7 +9,7 @@ namespace RenderDemo.Pages
{
public class GlyphRunPage : UserControl
{
private DrawingPresenter _drawingPresenter;
private Image _imageControl;
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
@ -25,7 +25,8 @@ namespace RenderDemo.Pages
{
AvaloniaXamlLoader.Load(this);
_drawingPresenter = this.FindControl<DrawingPresenter>("drawingPresenter");
_imageControl = this.FindControl<Image>("imageControl");
_imageControl.Source = new DrawingImage();
DispatcherTimer.Run(() =>
{
@ -73,7 +74,7 @@ namespace RenderDemo.Pages
drawingGroup.Children.Add(geometryDrawing);
_drawingPresenter.Drawing = drawingGroup;
(_imageControl.Source as DrawingImage).Drawing = drawingGroup;
}
}
}

2
samples/Sandbox/Program.cs

@ -10,7 +10,7 @@ namespace Sandbox
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToDebug()
.LogToTrace()
.StartWithClassicDesktopLifetime(args);
}
}

8
samples/VirtualizationDemo/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace VirtualizationDemo
@ -9,5 +10,12 @@ namespace VirtualizationDemo
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
}
}

20
samples/VirtualizationDemo/Program.cs

@ -1,19 +1,17 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia;
using Avalonia.ReactiveUI;
namespace VirtualizationDemo
{
class Program
{
static void Main(string[] args)
{
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToDebug()
.Start<MainWindow>();
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
}

8
samples/interop/Direct3DInteropSample/App.paml.cs

@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
namespace Direct3DInteropSample
@ -9,5 +10,12 @@ namespace Direct3DInteropSample
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
}
}

21
samples/interop/Direct3DInteropSample/Program.cs

@ -1,19 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia;
using Avalonia;
namespace Direct3DInteropSample
{
class Program
{
static void Main(string[] args)
{
AppBuilder.Configure<App>()
.With(new Win32PlatformOptions {UseDeferredRendering = false})
.UseWin32().UseDirect2D1().Start<MainWindow>();
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.With(new Win32PlatformOptions { UseDeferredRendering = false })
.UseWin32()
.UseDirect2D1();
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
}

3
samples/interop/NativeEmbedSample/NativeEmbedSample.csproj

@ -9,11 +9,10 @@
<ItemGroup>
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
<ProjectReference Include="..\..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType>

4
src/Avalonia.Animation/Properties/AssemblyInfo.cs

@ -6,5 +6,5 @@ using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")]
[assembly: InternalsVisibleTo("Avalonia.LeakTests")]
[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

3
src/Avalonia.Base/ApiCompatBaseline.txt

@ -1,3 +1,4 @@
Compat issues with assembly Avalonia.Base:
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
Total Issues: 1
TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract.
Total Issues: 2

14
src/Avalonia.Base/Logging/DebugLogSink.cs → src/Avalonia.Base/Logging/TraceLogSink.cs

@ -6,12 +6,12 @@ using Avalonia.Utilities;
namespace Avalonia.Logging
{
public class DebugLogSink : ILogSink
public class TraceLogSink : ILogSink
{
private readonly LogEventLevel _level;
private readonly IList<string> _areas;
public DebugLogSink(
public TraceLogSink(
LogEventLevel minimumLevel,
IList<string> areas = null)
{
@ -28,7 +28,7 @@ namespace Avalonia.Logging
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<object, object, object>(area, messageTemplate, source));
Trace.WriteLine(Format<object, object, object>(area, messageTemplate, source));
}
}
@ -36,7 +36,7 @@ namespace Avalonia.Logging
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0));
Trace.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0));
}
}
@ -44,7 +44,7 @@ namespace Avalonia.Logging
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1));
Trace.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1));
}
}
@ -52,7 +52,7 @@ namespace Avalonia.Logging
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2));
Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2));
}
}
@ -60,7 +60,7 @@ namespace Avalonia.Logging
{
if (IsEnabled(level, area))
{
Debug.WriteLine(Format(area, messageTemplate, source, propertyValues));
Trace.WriteLine(Format(area, messageTemplate, source, propertyValues));
}
}

39
src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs

@ -0,0 +1,39 @@
using System;
namespace Avalonia.Metadata
{
/// <summary>
/// Use to predefine the prefix associated to an xml namespace in a xaml file
/// </summary>
/// <remarks>
/// example:
/// [assembly: XmlnsPrefix("https://github.com/avaloniaui", "av")]
/// xaml:
/// xmlns:av="https://github.com/avaloniaui"
/// </remarks>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class XmlnsPrefixAttribute : Attribute
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="xmlNamespace">XML namespce</param>
/// <param name="prefix">recommended prefix</param>
public XmlnsPrefixAttribute(string xmlNamespace, string prefix)
{
XmlNamespace = xmlNamespace ?? throw new ArgumentNullException(nameof(xmlNamespace));
Prefix = prefix ?? throw new ArgumentNullException(nameof(prefix));
}
/// <summary>
/// XML Namespace
/// </summary>
public string XmlNamespace { get; }
/// <summary>
/// New Xml Namespace
/// </summary>
public string Prefix { get; }
}
}

10
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -5,8 +5,8 @@ using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

2
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -59,7 +59,7 @@
</Compile>
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" PrivateAssets="All" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
</ItemGroup>
</Project>

8
src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs

@ -39,7 +39,9 @@ namespace Avalonia.Build.Tasks
var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
ProjectDirectory, OutputPath, VerifyIl, outputImportance);
ProjectDirectory, OutputPath, VerifyIl, outputImportance,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null
);
if (!res.Success)
return false;
if (!res.WrittenFile)
@ -73,6 +75,10 @@ namespace Avalonia.Build.Tasks
public string OutputPath { get; set; }
public bool VerifyIl { get; set; }
public string AssemblyOriginatorKeyFile { get; set; }
public bool SignAssembly { get; set; }
public bool DelaySign { get; set; }
public string ReportImportance { get; set; }

26
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -42,7 +42,7 @@ namespace Avalonia.Build.Tasks
}
public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory,
string output, bool verifyIl, MessageImportance logImportance)
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey)
{
var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input);
var asm = typeSystem.TargetAssemblyDefinition;
@ -345,6 +345,20 @@ namespace Avalonia.Build.Tasks
}
res.Remove();
}
// Technically that's a hack, but it fixes corert incompatibility caused by deterministic builds
int dupeCounter = 1;
foreach (var grp in typeDef.NestedTypes.GroupBy(x => x.Name))
{
if (grp.Count() > 1)
{
foreach (var dupe in grp)
dupe.Name += "_dup" + dupeCounter++;
}
}
return true;
}
@ -361,10 +375,12 @@ namespace Avalonia.Build.Tasks
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
asm.Write(output, new WriterParameters
{
WriteSymbols = asm.MainModule.HasSymbols
});
var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
if (!string.IsNullOrWhiteSpace(strongNameKey))
writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
asm.Write(output, writerParameters);
return new CompileResult(true, true);
}

1
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -665,6 +665,7 @@ namespace Avalonia.Controls
/// <param name="dataItem">
/// The data item represented by the row that contains the intended cell.
/// </param>
/// <param name="binding">When the method returns, contains the applied binding.</param>
/// <returns>
/// A new editing element that is bound to the column's <see cref="P:Avalonia.Controls.DataGridBoundColumn.Binding" /> property value.
/// </returns>

13
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -340,8 +340,6 @@ namespace Avalonia.Controls
if (OwningGrid != null && OwningGrid.ColumnHeaders != null)
{
args.Pointer.Capture(this);
_dragMode = DragMode.MouseDown;
_frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth();
_lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition);
@ -413,8 +411,9 @@ namespace Avalonia.Controls
}
//TODO DragEvents
internal void OnMouseMove(ref bool handled, Point mousePosition, Point mousePositionHeaders)
internal void OnMouseMove(PointerEventArgs args, Point mousePosition, Point mousePositionHeaders)
{
var handled = args.Handled;
if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null)
{
return;
@ -438,7 +437,10 @@ namespace Avalonia.Controls
}
_lastMousePositionHeaders = mousePositionHeaders;
if (args.Pointer.Captured != this && _dragMode == DragMode.Drag)
args.Pointer.Capture(this);
SetDragCursor(mousePosition);
}
@ -506,8 +508,7 @@ namespace Avalonia.Controls
Point mousePosition = e.GetPosition(this);
Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders);
bool handled = false;
OnMouseMove(ref handled, mousePosition, mousePositionHeaders);
OnMouseMove(e, mousePosition, mousePositionHeaders);
}
/// <summary>

4
src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs

@ -2,8 +2,8 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")]

8
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -8,6 +8,12 @@ MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(A
TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract.
@ -17,4 +23,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalo
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
Total Issues: 18
Total Issues: 24

13
src/Avalonia.Controls/ContextMenu.cs

@ -62,6 +62,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
/// <summary>
/// Defines the <see cref="WindowManagerAddShadowHint"/> property.
/// </summary>
public static readonly StyledProperty<bool> WindowManagerAddShadowHintProperty =
Popup.WindowManagerAddShadowHintProperty.AddOwner<ContextMenu>();
/// <summary>
/// Defines the <see cref="PlacementTarget"/> property.
/// </summary>
@ -158,6 +164,12 @@ namespace Avalonia.Controls
set { SetValue(PlacementModeProperty, value); }
}
public bool WindowManagerAddShadowHint
{
get { return GetValue(WindowManagerAddShadowHintProperty); }
set { SetValue(WindowManagerAddShadowHintProperty, value); }
}
/// <summary>
/// Gets or sets the the anchor rectangle within the parent that the context menu will be placed
/// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
@ -267,6 +279,7 @@ namespace Avalonia.Controls
PlacementTarget = PlacementTarget ?? control,
IsLightDismissEnabled = true,
OverlayDismissEventPassThrough = true,
WindowManagerAddShadowHint = WindowManagerAddShadowHint,
};
_popup.Opened += PopupOpened;

2
src/Avalonia.Controls/ItemsControl.cs

@ -169,7 +169,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="items">The collection.</param>
/// <param name="index">The index.</param>
/// <returns>The index of the item or -1 if the item was not found.</returns>
/// <returns>The item at the given index or null if the index is out of bounds.</returns>
protected static object ElementAt(IEnumerable items, int index)
{
if (index != -1 && index < items.Count())

19
src/Avalonia.Controls/LoggingExtensions.cs

@ -1,25 +1,36 @@
using Avalonia.Controls;
using System;
using Avalonia.Controls;
using Avalonia.Logging;
namespace Avalonia
{
public static class LoggingExtensions
{
[Obsolete("Use LogToTrace")]
public static T LogToDebug<T>(
this T builder,
LogEventLevel level = LogEventLevel.Warning,
params string[] areas)
where T : AppBuilderBase<T>, new()
{
return LogToTrace(builder, level, areas);
}
/// <summary>
/// Logs Avalonia events to the <see cref="System.Diagnostics.Debug"/> sink.
/// Logs Avalonia events to the <see cref="System.Diagnostics.Trace"/> sink.
/// </summary>
/// <typeparam name="T">The application class type.</typeparam>
/// <param name="builder">The app builder instance.</param>
/// <param name="level">The minimum level to log.</param>
/// <param name="areas">The areas to log. Valid values are listed in <see cref="LogArea"/>.</param>
/// <returns>The app builder instance.</returns>
public static T LogToDebug<T>(
public static T LogToTrace<T>(
this T builder,
LogEventLevel level = LogEventLevel.Warning,
params string[] areas)
where T : AppBuilderBase<T>, new()
{
Logger.Sink = new DebugLogSink(level, areas);
Logger.Sink = new TraceLogSink(level, areas);
return builder;
}
}

7
src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs

@ -512,6 +512,13 @@ namespace Avalonia.Controls.Presenters
var generator = Owner.ItemContainerGenerator;
var newOffset = -1.0;
//better not trigger any container generation/recycle while or layout stuff
//before panel is attached/visible
if (!panel.IsAttachedToVisualTree)
{
return null;
}
if (!panel.IsMeasureValid && panel.PreviousMeasure.HasValue)
{
//before any kind of scrolling we need to make sure panel measure is valid

20
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -4,6 +4,7 @@ using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Threading;
using Avalonia.VisualTree;
using Avalonia.Layout;
namespace Avalonia.Controls.Presenters
{
@ -312,7 +313,24 @@ namespace Avalonia.Controls.Presenters
context.FillRectangle(background, new Rect(Bounds.Size));
}
context.DrawText(Foreground, new Point(), FormattedText);
double top = 0;
var textSize = FormattedText.Bounds.Size;
if (Bounds.Height < textSize.Height)
{
switch (VerticalAlignment)
{
case VerticalAlignment.Center:
top += (Bounds.Height - textSize.Height) / 2;
break;
case VerticalAlignment.Bottom:
top += (Bounds.Height - textSize.Height);
break;
}
}
context.DrawText(Foreground, new Point(0, top), FormattedText);
}
public override void Render(DrawingContext context)

1
src/Avalonia.Controls/Primitives/IPopupHost.cs

@ -47,6 +47,7 @@ namespace Avalonia.Controls.Primitives
/// <param name="offset">The offset, in device-independent pixels.</param>
/// <param name="anchor">The anchor point.</param>
/// <param name="gravity">The popup gravity.</param>
/// <param name="constraintAdjustment">Defines how a popup position will be adjusted if the unadjusted position would result in the popup being partly constrained.</param>
/// <param name="rect">
/// The anchor rect. If null, the bounds of <paramref name="target"/> will be used.
/// </param>

34
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -354,19 +354,15 @@ namespace Avalonia.Controls.Primitives
/// </summary>
/// <param name="eventSource">The control that raised the event.</param>
/// <returns>The container or null if the event did not originate in a container.</returns>
protected IControl? GetContainerFromEventSource(IInteractive eventSource)
protected IControl? GetContainerFromEventSource(IInteractive? eventSource)
{
var parent = (IVisual)eventSource;
while (parent != null)
for (var current = eventSource as IVisual; current != null; current = current.VisualParent)
{
if (parent is IControl control && control.LogicalParent == this
&& ItemContainerGenerator?.IndexFromContainer(control) != -1)
if (current is IControl control && control.LogicalParent == this &&
ItemContainerGenerator?.IndexFromContainer(control) != -1)
{
return control;
}
parent = parent.VisualParent;
}
return null;
@ -670,7 +666,7 @@ namespace Avalonia.Controls.Primitives
/// false.
/// </returns>
protected bool UpdateSelectionFromEventSource(
IInteractive eventSource,
IInteractive? eventSource,
bool select = true,
bool rangeModifier = false,
bool toggleModifier = false,
@ -794,18 +790,13 @@ namespace Avalonia.Controls.Primitives
/// <param name="e">The event.</param>
private void ContainerSelectionChanged(RoutedEventArgs e)
{
if (!_ignoreContainerSelectionChanged)
if (!_ignoreContainerSelectionChanged &&
e.Source is IControl control &&
e.Source is ISelectable selectable &&
control.LogicalParent == this &&
ItemContainerGenerator?.IndexFromContainer(control) != -1)
{
var control = e.Source as IControl;
var selectable = e.Source as ISelectable;
if (control != null &&
selectable != null &&
control.LogicalParent == this &&
ItemContainerGenerator?.IndexFromContainer(control) != -1)
{
UpdateSelection(control, selectable.IsSelected);
}
UpdateSelection(control, selectable.IsSelected);
}
if (e.Source != this)
@ -824,12 +815,11 @@ namespace Avalonia.Controls.Primitives
{
try
{
var selectable = container as ISelectable;
bool result;
_ignoreContainerSelectionChanged = true;
if (selectable != null)
if (container is ISelectable selectable)
{
result = selectable.IsSelected;
selectable.IsSelected = selected;

4
src/Avalonia.Controls/Properties/AssemblyInfo.cs

@ -2,8 +2,8 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport")]
[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]

44
src/Avalonia.Controls/Shapes/Shape.cs

@ -62,7 +62,6 @@ namespace Avalonia.Controls.Shapes
private Matrix _transform = Matrix.Identity;
private Geometry? _definingGeometry;
private Geometry? _renderedGeometry;
private bool _calculateTransformOnArrange;
static Shape()
{
@ -248,52 +247,21 @@ namespace Avalonia.Controls.Shapes
protected override Size MeasureOverride(Size availableSize)
{
bool deferCalculateTransform;
switch (Stretch)
if (DefiningGeometry is null)
{
case Stretch.Fill:
case Stretch.UniformToFill:
deferCalculateTransform = double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height);
break;
case Stretch.Uniform:
deferCalculateTransform = double.IsInfinity(availableSize.Width) && double.IsInfinity(availableSize.Height);
break;
case Stretch.None:
default:
deferCalculateTransform = false;
break;
return default;
}
if (deferCalculateTransform)
{
_calculateTransformOnArrange = true;
return DefiningGeometry?.Bounds.Size ?? Size.Empty;
}
else
{
_calculateTransformOnArrange = false;
return CalculateShapeSizeAndSetTransform(availableSize);
}
return CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch).size;
}
protected override Size ArrangeOverride(Size finalSize)
{
if (_calculateTransformOnArrange)
{
_calculateTransformOnArrange = false;
CalculateShapeSizeAndSetTransform(finalSize);
}
return finalSize;
}
private Size CalculateShapeSizeAndSetTransform(Size availableSize)
{
if (DefiningGeometry != null)
{
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
// will multiply the stroke thickness as well, which isn't correct.
var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);
var (_, transform) = CalculateSizeAndTransform(finalSize, DefiningGeometry.Bounds, Stretch);
if (_transform != transform)
{
@ -301,13 +269,13 @@ namespace Avalonia.Controls.Shapes
_renderedGeometry = null;
}
return size;
return finalSize;
}
return Size.Empty;
}
internal static (Size, Matrix) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch)
internal static (Size size, Matrix transform) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch)
{
Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom);
Matrix translate = Matrix.Identity;

54
src/Avalonia.Controls/SplitView.cs

@ -9,6 +9,8 @@ using Avalonia.Platform;
using Avalonia.VisualTree;
using System;
using System.Reactive.Disposables;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
namespace Avalonia.Controls
{
@ -78,7 +80,7 @@ namespace Avalonia.Controls
[PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")]
[PseudoClasses(":left", ":right")]
[PseudoClasses(":lightdismiss")]
public class SplitView : TemplatedControl
public class SplitView : ContentControl
{
/*
Pseudo classes & combos
@ -87,12 +89,6 @@ namespace Avalonia.Controls
:left :right
*/
/// <summary>
/// Defines the <see cref="Content"/> property
/// </summary>
public static readonly StyledProperty<IControl> ContentProperty =
AvaloniaProperty.Register<SplitView, IControl>(nameof(Content));
/// <summary>
/// Defines the <see cref="CompactPaneLength"/> property
/// </summary>
@ -133,8 +129,14 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Pane"/> property
/// </summary>
public static readonly StyledProperty<IControl> PaneProperty =
AvaloniaProperty.Register<SplitView, IControl>(nameof(Pane));
public static readonly StyledProperty<object?> PaneProperty =
AvaloniaProperty.Register<SplitView, object?>(nameof(Pane));
/// <summary>
/// Defines the <see cref="HeaderTemplate"/> property.
/// </summary>
public static readonly StyledProperty<IDataTemplate?> PaneTemplateProperty =
AvaloniaProperty.Register<HeaderedContentControl, IDataTemplate?>(nameof(PaneTemplate));
/// <summary>
/// Defines the <see cref="UseLightDismissOverlayMode"/> property
@ -166,16 +168,7 @@ namespace Avalonia.Controls
CompactPaneLengthProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnCompactPaneLengthChanged(v));
PanePlacementProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnPanePlacementChanged(v));
DisplayModeProperty.Changed.AddClassHandler<SplitView>((x, v) => x.OnDisplayModeChanged(v));
}
/// <summary>
/// Gets or sets the content of the SplitView
/// </summary>
[Content]
public IControl Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
/// <summary>
@ -265,11 +258,20 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the Pane for the SplitView
/// </summary>
public IControl Pane
public object Pane
{
get => GetValue(PaneProperty);
set => SetValue(PaneProperty, value);
}
/// <summary>
/// Gets or sets the data template used to display the header content of the control.
/// </summary>
public IDataTemplate? PaneTemplate
{
get => GetValue(PaneTemplateProperty);
set => SetValue(PaneTemplateProperty, value);
}
/// <summary>
/// Gets or sets whether WinUI equivalent LightDismissOverlayMode is enabled
@ -312,6 +314,18 @@ namespace Avalonia.Controls
/// </summary>
public event EventHandler<EventArgs> PaneOpening;
protected override bool RegisterContentPresenter(IContentPresenter presenter)
{
var result = base.RegisterContentPresenter(presenter);
if (presenter.Name == "PART_PanePresenter")
{
return true;
}
return result;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);

23
src/Avalonia.Controls/TextBlock.cs

@ -3,6 +3,7 @@ using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
using Avalonia.Layout;
namespace Avalonia.Controls
{
@ -427,14 +428,32 @@ namespace Avalonia.Controls
case TextAlignment.Center:
offsetX = (width - TextLayout.Size.Width) / 2;
break;
case TextAlignment.Right:
offsetX = width - TextLayout.Size.Width;
offsetX = width - TextLayout.Size.Width;
break;
}
var padding = Padding;
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top)))
var top = padding.Top;
var textSize = TextLayout.Size;
if (Bounds.Height < textSize.Height)
{
switch (VerticalAlignment)
{
case VerticalAlignment.Center:
top += (Bounds.Height - textSize.Height) / 2;
break;
case VerticalAlignment.Bottom:
top += (Bounds.Height - textSize.Height);
break;
}
}
using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, top)))
{
TextLayout.Draw(context);
}

2
src/Avalonia.Controls/Window.cs

@ -451,7 +451,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="dialogResult">The dialog result.</param>
/// <remarks>
/// When the window is shown with the <see cref="ShowDialog{TResult}(IWindowImpl)"/>
/// When the window is shown with the <see cref="ShowDialog{TResult}(Window)"/>
/// or <see cref="ShowDialog{TResult}(Window)"/> method, the
/// resulting task will produce the <see cref="_dialogResult"/> value when the window
/// is closed.

1
src/Avalonia.Dialogs/ApiCompatBaseline.txt

@ -0,0 +1 @@
Total Issues: 0

4
src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj

@ -6,9 +6,7 @@
<ItemGroup>
<ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
<PackageReference Include="Tmds.DBus" Version="0.9.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Tmds.DBus" Version="0.7.0" />
</ItemGroup>
</Project>

5
src/Avalonia.Input/KeyGesture.cs

@ -144,7 +144,10 @@ namespace Avalonia.Input
return s.ToString();
}
public bool Matches(KeyEventArgs keyEvent) => ResolveNumPadOperationKey(keyEvent.Key) == Key && keyEvent.KeyModifiers == KeyModifiers;
public bool Matches(KeyEventArgs keyEvent) =>
keyEvent != null &&
keyEvent.KeyModifiers == KeyModifiers &&
ResolveNumPadOperationKey(keyEvent.Key) == ResolveNumPadOperationKey(Key);
// TODO: Move that to external key parser
private static Key ParseKey(string key)

20
src/Avalonia.Input/MouseDevice.cs

@ -19,6 +19,7 @@ namespace Avalonia.Input
private readonly Pointer _pointer;
private bool _disposed;
private PixelPoint? _position;
public MouseDevice(Pointer? pointer = null)
{
@ -39,10 +40,11 @@ namespace Avalonia.Input
/// <summary>
/// Gets the mouse position, in screen coordinates.
/// </summary>
[Obsolete("Use events instead")]
public PixelPoint Position
{
get;
protected set;
get => _position ?? new PixelPoint(-1, -1);
protected set => _position = value;
}
/// <summary>
@ -91,7 +93,16 @@ namespace Avalonia.Input
public void SceneInvalidated(IInputRoot root, Rect rect)
{
var clientPoint = root.PointToClient(Position);
// Pointer is outside of the target area
if (_position == null )
{
if (root.PointerOverElement != null)
ClearPointerOver(this, 0, root, PointerPointProperties.None, KeyModifiers.None);
return;
}
var clientPoint = root.PointToClient(_position.Value);
if (rect.Contains(clientPoint))
{
@ -132,7 +143,7 @@ namespace Avalonia.Input
if(mouse._disposed)
return;
Position = e.Root.PointToScreen(e.Position);
_position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e);
var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers);
switch (e.Type)
@ -176,6 +187,7 @@ namespace Avalonia.Input
device = device ?? throw new ArgumentNullException(nameof(device));
root = root ?? throw new ArgumentNullException(nameof(root));
_position = null;
ClearPointerOver(this, timestamp, root, properties, inputModifiers);
}

2
src/Avalonia.Layout/Properties/AssemblyInfo.cs

@ -1,7 +1,7 @@
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: InternalsVisibleTo("Avalonia.Layout.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Layout.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Layout")]

9
src/Avalonia.Native/WindowImplBase.cs

@ -251,6 +251,9 @@ namespace Avalonia.Native
public bool RawTextInputEvent(uint timeStamp, string text)
{
if (_inputRoot is null)
return false;
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
var args = new RawTextInputEventArgs(_keyboard, timeStamp, _inputRoot, text);
@ -262,6 +265,9 @@ namespace Avalonia.Native
public bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key)
{
if (_inputRoot is null)
return false;
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
var args = new RawKeyEventArgs(_keyboard, timeStamp, _inputRoot, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers);
@ -278,6 +284,9 @@ namespace Avalonia.Native
public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
{
if (_inputRoot is null)
return;
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
switch (type)

10
src/Avalonia.OpenGL/Angle/AngleEglInterface.cs

@ -1,15 +1,13 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
namespace Avalonia.OpenGL.Angle
{
public class AngleEglInterface : EglInterface
{
[DllImport("libegl.dll", CharSet = CharSet.Ansi)]
static extern IntPtr eglGetProcAddress(string proc);
[DllImport("av_libGLESv2.dll", CharSet = CharSet.Ansi)]
static extern IntPtr EGL_GetProcAddress(string proc);
public AngleEglInterface() : base(LoadAngle())
{
@ -20,14 +18,14 @@ namespace Avalonia.OpenGL.Angle
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var disp = eglGetProcAddress("eglGetPlatformDisplayEXT");
var disp = EGL_GetProcAddress("eglGetPlatformDisplayEXT");
if (disp == IntPtr.Zero)
{
throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point");
}
return eglGetProcAddress;
return EGL_GetProcAddress;
}
throw new PlatformNotSupportedException();

9
src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs

@ -82,7 +82,14 @@ namespace Avalonia.OpenGL.Angle
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE });
}
public EglSurface WrapDirect3D11Texture(EglPlatformOpenGlInterface egl, IntPtr handle, int offsetX, int offsetY, int width, int height)
{
if (PlatformApi != AngleOptions.PlatformApi.DirectX11)
throw new InvalidOperationException("Current platform API is " + PlatformApi);
return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, EGL_TEXTURE_OFFSET_X_ANGLE, offsetX, EGL_TEXTURE_OFFSET_Y_ANGLE, offsetY, EGL_NONE });
}
}
}

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

@ -205,5 +205,11 @@ namespace Avalonia.OpenGL.Egl
public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
public const int EGL_D3D_TEXTURE_ANGLE = 0x33A3;
public const int EGL_TEXTURE_OFFSET_X_ANGLE = 0x3490;
public const int EGL_TEXTURE_OFFSET_Y_ANGLE = 0x3491;
public const int EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE = 0x33A6;
}
}

1
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Avalonia.ReactiveUI</PackageId>
<SignAssembly>True</SignAssembly>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />

2
src/Avalonia.Styling/Properties/AssemblyInfo.cs

@ -5,4 +5,4 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.LogicalTree")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")]
[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

8
src/Avalonia.Themes.Default/SplitView.xaml

@ -32,12 +32,12 @@
ClipToBounds="True"
HorizontalAlignment="Left"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}" />
<Rectangle Name="HCPaneBorder" Fill="{DynamicResource SystemControlForegroundTransparentBrush}" Width="1" HorizontalAlignment="Right" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
@ -106,14 +106,14 @@
ClipToBounds="True"
HorizontalAlignment="Right"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}"/>
<Rectangle Name="HCPaneBorder"
Fill="{DynamicResource SystemControlForegroundTransparentBrush}"
Width="1" HorizontalAlignment="Left" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>

8
src/Avalonia.Themes.Fluent/SplitView.xaml

@ -32,12 +32,12 @@
ClipToBounds="True"
HorizontalAlignment="Left"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}" />
<Rectangle Name="HCPaneBorder" Fill="{DynamicResource SystemControlForegroundTransparentBrush}" Width="1" HorizontalAlignment="Right" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>
@ -106,14 +106,14 @@
ClipToBounds="True"
HorizontalAlignment="Right"
ZIndex="100">
<Border Child="{TemplateBinding Pane}"/>
<ContentPresenter x:Name="PART_PanePresenter" Content="{TemplateBinding Pane}" ContentTemplate="{TemplateBinding PaneTemplate}"/>
<Rectangle Name="HCPaneBorder"
Fill="{DynamicResource SystemControlForegroundTransparentBrush}"
Width="1" HorizontalAlignment="Left" />
</Panel>
<Panel Name="ContentRoot">
<Border Child="{TemplateBinding Content}" />
<ContentPresenter x:Name="PART_ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<Rectangle Name="LightDismissLayer"/>
</Panel>

4
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -2,6 +2,8 @@ Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public void Avalonia.Media.DrawingContext.DrawGlyphRun(Avalonia.Media.IBrush, Avalonia.Media.GlyphRun, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.GetOrAddTypeface(Avalonia.Media.FontFamily, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Media.Typeface Avalonia.Media.FontManager.MatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.Geometry.GetRenderBounds(Avalonia.Media.Pen)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Boolean Avalonia.Media.Geometry.StrokeContains(Avalonia.Media.Pen, Avalonia.Point)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Rect Avalonia.Media.GlyphRun.Bounds.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Point> Avalonia.StyledProperty<Avalonia.Point> Avalonia.Media.GlyphRunDrawing.BaselineOriginProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Point Avalonia.Media.GlyphRunDrawing.BaselineOrigin.get()' does not exist in the implementation but it does exist in the contract.
@ -34,4 +36,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalon
MembersMustExist : Member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Fonts.FontKey)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IFontManagerImpl.TryMatchCharacter(System.Int32, Avalonia.Media.FontStyle, Avalonia.Media.FontWeight, Avalonia.Media.FontFamily, System.Globalization.CultureInfo, Avalonia.Media.Typeface)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public Avalonia.Utilities.IRef<Avalonia.Platform.IRenderTargetBitmapImpl> Avalonia.Rendering.RenderLayer.Bitmap.get()' does not exist in the implementation but it does exist in the contract.
Total Issues: 35
Total Issues: 37

14
src/Avalonia.Visuals/Media/Drawing.cs

@ -1,11 +1,19 @@
using Avalonia.Platform;
namespace Avalonia.Media
namespace Avalonia.Media
{
/// <summary>
/// Abstract class that describes a 2-D drawing.
/// </summary>
public abstract class Drawing : AvaloniaObject
{
/// <summary>
/// Draws this drawing to the given <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
public abstract void Draw(DrawingContext context);
/// <summary>
/// Gets the drawing's bounding rectangle.
/// </summary>
public abstract Rect GetBounds();
}
}

4
src/Avalonia.Visuals/Media/Geometry.cs

@ -84,7 +84,7 @@ namespace Avalonia.Media
/// </summary>
/// <param name="pen">The stroke thickness.</param>
/// <returns>The bounding rectangle.</returns>
public Rect GetRenderBounds(Pen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty;
public Rect GetRenderBounds(IPen pen) => PlatformImpl?.GetRenderBounds(pen) ?? Rect.Empty;
/// <summary>
/// Indicates whether the geometry's fill contains the specified point.
@ -102,7 +102,7 @@ namespace Avalonia.Media
/// <param name="pen">The pen to use.</param>
/// <param name="point">The point.</param>
/// <returns><c>true</c> if the geometry contains the point; otherwise, <c>false</c>.</returns>
public bool StrokeContains(Pen pen, Point point)
public bool StrokeContains(IPen pen, Point point)
{
return PlatformImpl?.StrokeContains(pen, point) == true;
}

44
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@ -1,12 +1,38 @@
using Avalonia.Metadata;
using Avalonia.Media.Immutable;
using Avalonia.Metadata;
namespace Avalonia.Media
{
/// <summary>
/// Represents a drawing operation that combines
/// a geometry with and brush and/or pen to produce rendered content.
/// </summary>
public class GeometryDrawing : Drawing
{
// Adding the Pen's stroke thickness here could yield wrong results due to transforms.
private static readonly IPen s_boundsPen = new ImmutablePen(Colors.Black.ToUint32(), 0);
/// <summary>
/// Defines the <see cref="Geometry"/> property.
/// </summary>
public static readonly StyledProperty<Geometry> GeometryProperty =
AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry));
/// <summary>
/// Defines the <see cref="Brush"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
/// <summary>
/// Defines the <see cref="Pen"/> property.
/// </summary>
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.Geometry"/> that describes the shape of this <see cref="GeometryDrawing"/>.
/// </summary>
[Content]
public Geometry Geometry
{
@ -14,18 +40,18 @@ namespace Avalonia.Media
set => SetValue(GeometryProperty, value);
}
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IBrush"/> used to fill the interior of the shape described by this <see cref="GeometryDrawing"/>.
/// </summary>
public IBrush Brush
{
get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value);
}
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
/// <summary>
/// Gets or sets the <see cref="Avalonia.Media.IPen"/> used to stroke this <see cref="GeometryDrawing"/>.
/// </summary>
public IPen Pen
{
get => GetValue(PenProperty);
@ -42,9 +68,7 @@ namespace Avalonia.Media
public override Rect GetBounds()
{
// adding the Pen's stroke thickness here could yield wrong results due to transforms
var pen = new Pen(Brushes.Black, 0);
return Geometry?.GetRenderBounds(pen) ?? new Rect();
return Geometry?.GetRenderBounds(s_boundsPen) ?? Rect.Empty;
}
}
}

1
src/Avalonia.Visuals/Media/Imaging/Bitmap.cs

@ -99,7 +99,6 @@ namespace Avalonia.Media.Imaging
/// Initializes a new instance of the <see cref="Bitmap"/> class.
/// </summary>
/// <param name="format">The pixel format.</param>
/// <param name="alphaFormat">The alpha format.</param>
/// <param name="data">The pointer to the source bytes.</param>
/// <param name="size">The size of the bitmap in device pixels.</param>
/// <param name="dpi">The DPI of the bitmap.</param>

2
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -69,7 +69,7 @@ namespace Avalonia.Platform
/// If the pen is null, then no stoke is performed. If both the pen and the brush are null, then the drawing is not visible.
/// </remarks>
void DrawRectangle(IBrush brush, IPen pen, RoundedRect rect,
BoxShadows boxShadow = default);
BoxShadows boxShadows = default);
/// <summary>
/// Draws text.

8
src/Avalonia.Visuals/Properties/AssemblyInfo.cs

@ -2,13 +2,13 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using Avalonia.Metadata;
[assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Visuals.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Imaging")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")]
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

4
src/Avalonia.Visuals/Rendering/RenderLayer.cs

@ -30,12 +30,12 @@ namespace Avalonia.Rendering
{
if (Size != size || Scaling != scaling)
{
Bitmap.Dispose();
var resized = RefCountable.Create(drawingContext.CreateLayer(size));
using (var context = resized.Item.CreateDrawingContext(null))
{
context.Clear(Colors.Transparent);
Bitmap.Dispose();
context.Clear(default);
Bitmap = resized;
Scaling = scaling;

7
src/Avalonia.Visuals/Rendering/SceneGraph/ExperimentalAcrylicNode.cs

@ -13,10 +13,9 @@ namespace Avalonia.Rendering.SceneGraph
/// <summary>
/// Initializes a new instance of the <see cref="RectangleNode"/> class.
/// </summary>
/// <param name="transform">The transform.</param>
/// <param name="transform">The transform.</param>
/// <param name="material"></param>
/// <param name="rect">The rectangle to draw.</param>
/// <param name="boxShadow">The box shadow parameters</param>
/// <param name="childScenes">Child scenes for drawing visual brushes.</param>
public ExperimentalAcrylicNode(
Matrix transform,
IExperimentalAcrylicMaterial material,
@ -44,7 +43,7 @@ namespace Avalonia.Rendering.SceneGraph
/// Determines if this draw operation equals another.
/// </summary>
/// <param name="transform">The transform of the other draw operation.</param>
/// <param name="brush">The fill of the other draw operation.</param>
/// <param name="material">The fill of the other draw operation.</param>
/// <param name="rect">The rectangle of the other draw operation.</param>
/// <returns>True if the draw operations are the same, otherwise false.</returns>
/// <remarks>

1
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs

@ -63,7 +63,6 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="brush">The fill of the other draw operation.</param>
/// <param name="pen">The stroke of the other draw operation.</param>
/// <param name="geometry">The geometry of the other draw operation.</param>
/// <param name="boxShadow">The box shadow parameters</param>
/// <returns>True if the draw operations are the same, otherwise false.</returns>
/// <remarks>
/// The properties of the other draw operation are passed in as arguments to prevent

2
src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs

@ -73,7 +73,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="brush">The fill of the other draw operation.</param>
/// <param name="pen">The stroke of the other draw operation.</param>
/// <param name="rect">The rectangle of the other draw operation.</param>
/// <param name="boxShadow">The box shadow parameters of the other draw operation</param>
/// <param name="boxShadows">The box shadow parameters of the other draw operation</param>
/// <returns>True if the draw operations are the same, otherwise false.</returns>
/// <remarks>
/// The properties of the other draw operation are passed in as arguments to prevent

84
src/Avalonia.X11/XI2Manager.cs

@ -13,7 +13,10 @@ namespace Avalonia.X11
{
XiEventType.XI_Motion,
XiEventType.XI_ButtonPress,
XiEventType.XI_ButtonRelease
XiEventType.XI_ButtonRelease,
XiEventType.XI_Leave,
XiEventType.XI_Enter,
};
private static readonly XiEventType[] MultiTouchEventTypes = new XiEventType[]
@ -162,7 +165,9 @@ namespace Avalonia.X11
| XEventMask.Button4MotionMask
| XEventMask.Button5MotionMask
| XEventMask.ButtonPressMask
| XEventMask.ButtonReleaseMask;
| XEventMask.ButtonReleaseMask
| XEventMask.LeaveWindowMask
| XEventMask.EnterWindowMask;
}
public void OnWindowDestroyed(IntPtr xid) => _clients.Remove(xid);
@ -175,14 +180,39 @@ namespace Avalonia.X11
_pointerDevice.Update(changed->Classes, changed->NumClasses);
}
if ((xev->evtype >= XiEventType.XI_ButtonPress && xev->evtype <= XiEventType.XI_Motion)
|| (xev->evtype>=XiEventType.XI_TouchBegin&&xev->evtype<=XiEventType.XI_TouchEnd))
|| (xev->evtype >= XiEventType.XI_TouchBegin && xev->evtype <= XiEventType.XI_TouchEnd))
{
var dev = (XIDeviceEvent*)xev;
if (_clients.TryGetValue(dev->EventWindow, out var client))
OnDeviceEvent(client, new ParsedDeviceEvent(dev));
}
if (xev->evtype == XiEventType.XI_Leave || xev->evtype == XiEventType.XI_Enter)
{
var rev = (XIEnterLeaveEvent*)xev;
if (_clients.TryGetValue(rev->EventWindow, out var client))
OnEnterLeaveEvent(client, ref *rev);
}
}
void OnEnterLeaveEvent(IXI2Client client, ref XIEnterLeaveEvent ev)
{
if (ev.evtype == XiEventType.XI_Leave)
{
var buttons = ParsedDeviceEvent.ParseButtonState(ev.buttons.MaskLen, ev.buttons.Mask);
var detail = ev.detail;
if ((detail == XiEnterLeaveDetail.XINotifyNonlinearVirtual ||
detail == XiEnterLeaveDetail.XINotifyNonlinear ||
detail == XiEnterLeaveDetail.XINotifyVirtual)
&& buttons == default)
{
client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, (ulong)ev.time.ToInt64(),
client.InputRoot,
RawPointerEventType.LeaveWindow, new Point(ev.event_x, ev.event_y), buttons));
}
}
}
void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
@ -284,6 +314,29 @@ namespace Avalonia.X11
public int Detail { get; set; }
public bool Emulated { get; set; }
public Dictionary<int, double> Valuators { get; }
public static RawInputModifiers ParseButtonState(int len, byte* buttons)
{
RawInputModifiers rv = default;
if (len > 0)
{
if (XIMaskIsSet(buttons, 1))
rv |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
rv |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
rv |= RawInputModifiers.RightMouseButton;
if (len > 1)
{
if (XIMaskIsSet(buttons, 8))
rv |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
rv |= RawInputModifiers.XButton2MouseButton;
}
}
return rv;
}
public ParsedDeviceEvent(XIDeviceEvent* ev)
{
Type = ev->evtype;
@ -298,27 +351,16 @@ namespace Avalonia.X11
if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= RawInputModifiers.Meta;
if (ev->buttons.MaskLen > 0)
{
var buttons = ev->buttons.Mask;
if (XIMaskIsSet(buttons, 1))
Modifiers |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2))
Modifiers |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3))
Modifiers |= RawInputModifiers.RightMouseButton;
if (XIMaskIsSet(buttons, 8))
Modifiers |= RawInputModifiers.XButton1MouseButton;
if (XIMaskIsSet(buttons, 9))
Modifiers |= RawInputModifiers.XButton2MouseButton;
}
Modifiers = ParseButtonState(ev->buttons.MaskLen, ev->buttons.Mask);
Valuators = new Dictionary<int, double>();
Position = new Point(ev->event_x, ev->event_y);
var values = ev->valuators.Values;
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if(ev->valuators.Mask != null)
for (var c = 0; c < ev->valuators.MaskLen * 8; c++)
if (XIMaskIsSet(ev->valuators.Mask, c))
Valuators[c] = *values++;
if (Type == XiEventType.XI_ButtonPress || Type == XiEventType.XI_ButtonRelease)
Button = ev->detail;
Detail = ev->detail;

43
src/Avalonia.X11/XIStructs.cs

@ -236,6 +236,34 @@ namespace Avalonia.X11
public XIModifierState mods;
public XIModifierState group;
}
[StructLayout(LayoutKind.Sequential)]
unsafe struct XIEnterLeaveEvent
{
public XEventName type; /* GenericEvent */
public UIntPtr serial; /* # of last request processed by server */
public Bool send_event; /* true if this came from a SendEvent request */
public IntPtr display; /* Display the event was read from */
public int extension; /* XI extension offset */
public XiEventType evtype;
public IntPtr time;
public int deviceid;
public int sourceid;
public XiEnterLeaveDetail detail;
public IntPtr RootWindow;
public IntPtr EventWindow;
public IntPtr ChildWindow;
public double root_x;
public double root_y;
public double event_x;
public double event_y;
public int mode;
public int focus;
public int same_screen;
public XIButtonState buttons;
public XIModifierState mods;
public XIModifierState group;
}
[Flags]
public enum XiDeviceEventFlags : int
@ -286,5 +314,18 @@ namespace Avalonia.X11
XI_BarrierLeave = 26,
XI_LASTEVENT = XI_BarrierLeave,
}
enum XiEnterLeaveDetail
{
XINotifyAncestor = 0,
XINotifyVirtual = 1,
XINotifyInferior = 2,
XINotifyNonlinear = 3,
XINotifyNonlinearVirtual = 4,
XINotifyPointer = 5,
XINotifyPointerRoot = 6,
XINotifyDetailNone = 7
}
}

16
src/Linux/Avalonia.LinuxFramebuffer/Output/Drm.cs

@ -113,22 +113,22 @@ namespace Avalonia.LinuxFramebuffer.Output
[StructLayout(LayoutKind.Sequential)]
public struct drmModeConnector {
public uint connector_id;
public uint encoder_id; /**< Encoder currently connected to */
public uint encoder_id; // Encoder currently connected to
public uint connector_type;
public uint connector_type_id;
public DrmModeConnection connection;
public uint mmWidth, mmHeight; /**< HxW in millimeters */
public uint mmWidth, mmHeight; // HxW in millimeters
public DrmModeSubPixel subpixel;
public int count_modes;
public drmModeModeInfo* modes;
public int count_props;
public uint *props; /**< List of property ids */
public ulong *prop_values; /**< List of property values */
public uint *props; // List of property ids
public ulong *prop_values; // List of property values
public int count_encoders;
public uint *encoders; /**< List of encoder ids */
public uint *encoders; //List of encoder ids
}
[StructLayout(LayoutKind.Sequential)]
@ -143,14 +143,14 @@ namespace Avalonia.LinuxFramebuffer.Output
[StructLayout(LayoutKind.Sequential)]
public struct drmModeCrtc {
public uint crtc_id;
public uint buffer_id; /**< FB id to connect to 0 = disconnect */
public uint buffer_id; // FB id to connect to 0 = disconnect
public uint x, y; /**< Position on the framebuffer */
public uint x, y; // Position on the framebuffer
public uint width, height;
public int mode_valid;
public drmModeModeInfo mode;
public int gamma_size; /**< Number of gamma stops */
public int gamma_size; // Number of gamma stops
}

31
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs

@ -3,7 +3,6 @@ using System.IO;
using System.Reflection;
using System.Text;
using Avalonia.Markup.Xaml.XamlIl;
// ReSharper disable CheckNamespace
namespace Avalonia.Markup.Xaml
{
@ -13,10 +12,10 @@ namespace Avalonia.Markup.Xaml
/// Loads XAML from a string.
/// </summary>
/// <param name="xaml">The string containing the XAML.</param>
/// <param name="localAssembly">Default assembly for clr-namespace:</param>
/// <param name="rootInstance">
/// The optional instance into which the XAML should be loaded.
/// </param>
/// <param name="localAssembly">Default assembly for clr-namespace:.</param>
/// <param name="rootInstance">The optional instance into which the XAML should be loaded.</param>
/// <param name="uri">The URI of the XAML being loaded.</param>
/// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param>
/// <returns>The loaded object.</returns>
public static object Load(string xaml, Assembly localAssembly = null, object rootInstance = null, Uri uri = null, bool designMode = false)
{
@ -28,13 +27,35 @@ namespace Avalonia.Markup.Xaml
}
}
/// <summary>
/// Loads XAML from a stream.
/// </summary>
/// <param name="stream">The stream containing the XAML.</param>
/// <param name="localAssembly">Default assembly for clr-namespace:</param>
/// <param name="rootInstance">The optional instance into which the XAML should be loaded.</param>
/// <param name="uri">The URI of the XAML being loaded.</param>
/// <param name="designMode">Indicates whether the XAML is being loaded in design mode.</param>
/// <returns>The loaded object.</returns>
public static object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null,
bool designMode = false)
=> AvaloniaXamlIlRuntimeCompiler.Load(stream, localAssembly, rootInstance, uri, designMode);
/// <summary>
/// Parse XAML from a string.
/// </summary>
/// <param name="xaml">The string containing the XAML.</param>
/// <param name="localAssembly">Default assembly for clr-namespace:.</param>
/// <returns>The loaded object.</returns>
public static object Parse(string xaml, Assembly localAssembly = null)
=> Load(xaml, localAssembly);
/// <summary>
/// Parse XAML from a string.
/// </summary>
/// <typeparam name="T">The type of the returned object.</typeparam>
/// <param name="xaml">>The string containing the XAML.</param>
/// <param name="localAssembly">>Default assembly for clr-namespace:.</param>
/// <returns>The loaded object.</returns>
public static T Parse<T>(string xaml, Assembly localAssembly = null)
=> (T)Parse(xaml, localAssembly);

2
src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs

@ -5,5 +5,5 @@ using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Templates")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

2
src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs

@ -4,4 +4,4 @@ using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Data")]
[assembly: InternalsVisibleTo("Avalonia.Markup.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Markup.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

8
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -36,6 +36,7 @@ namespace Avalonia.Skia
private readonly SKPaint _fillPaint = new SKPaint();
private readonly SKPaint _boxShadowPaint = new SKPaint();
private static SKShader s_acrylicNoiseShader;
private readonly ISkiaGpuRenderSession _session;
/// <summary>
/// Context create info.
@ -76,6 +77,8 @@ namespace Avalonia.Skia
/// Skia GPU provider context (optional)
/// </summary>
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession CurrentSession;
}
/// <summary>
@ -96,6 +99,8 @@ namespace Avalonia.Skia
Surface = createInfo.Surface;
Canvas = createInfo.Canvas ?? createInfo.Surface?.Canvas;
_session = createInfo.CurrentSession;
if (Canvas == null)
{
throw new ArgumentException("Invalid create info - no Canvas provided", nameof(createInfo));
@ -969,7 +974,8 @@ namespace Avalonia.Skia
Format = format,
DisableTextLcdRendering = !_canTextUseLcdRendering,
GrContext = _grContext,
Gpu = _gpu
Gpu = _gpu,
Session = _session
};
return new SurfaceRenderTarget(createInfo);

44
src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

@ -1,6 +1,5 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Media;
using Avalonia.Platform;
using HarfBuzzSharp;
using SkiaSharp;
@ -24,40 +23,33 @@ namespace Avalonia.Skia
Font.SetFunctionsOpenType();
Font.GetScale(out var xScale, out _);
DesignEmHeight = (short)Typeface.UnitsPerEm;
DesignEmHeight = (short)xScale;
var metrics = Typeface.ToFont().Metrics;
if (!Font.TryGetHorizontalFontExtents(out var fontExtents))
{
Font.TryGetVerticalFontExtents(out fontExtents);
}
const double defaultFontRenderingEmSize = 12.0;
Ascent = -fontExtents.Ascender;
Ascent = (int)(metrics.Ascent / defaultFontRenderingEmSize * Typeface.UnitsPerEm);
Descent = -fontExtents.Descender;
Descent = (int)(metrics.Descent / defaultFontRenderingEmSize * Typeface.UnitsPerEm);
LineGap = fontExtents.LineGap;
LineGap = (int)(metrics.Leading / defaultFontRenderingEmSize * Typeface.UnitsPerEm);
if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineOffset, out var underlinePosition))
{
UnderlinePosition = underlinePosition;
}
UnderlinePosition = metrics.UnderlinePosition != null ?
(int)(metrics.UnderlinePosition / defaultFontRenderingEmSize * Typeface.UnitsPerEm) :
0;
if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineSize, out var underlineThickness))
{
UnderlineThickness = underlineThickness;
}
UnderlineThickness = metrics.UnderlineThickness != null ?
(int)(metrics.UnderlineThickness / defaultFontRenderingEmSize * Typeface.UnitsPerEm) :
0;
if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutOffset, out var strikethroughPosition))
{
StrikethroughPosition = strikethroughPosition;
}
StrikethroughPosition = metrics.StrikeoutPosition != null ?
(int)(metrics.StrikeoutPosition / defaultFontRenderingEmSize * Typeface.UnitsPerEm) :
0;
if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutSize, out var strikethroughThickness))
{
StrikethroughThickness = strikethroughThickness;
}
StrikethroughThickness = metrics.StrikeoutThickness != null ?
(int)(metrics.StrikeoutThickness / defaultFontRenderingEmSize * Typeface.UnitsPerEm) :
0;
IsFixedPitch = Typeface.IsFixedPitch;
}

2
src/Skia/Avalonia.Skia/Gpu/ISkiaGpu.cs

@ -21,7 +21,7 @@ namespace Avalonia.Skia
/// Creates an offscreen render target surface
/// </summary>
/// <param name="size">size in pixels</param>
ISkiaSurface TryCreateSurface(PixelSize size);
ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session);
}
public interface ISkiaSurface : IDisposable

2
src/Skia/Avalonia.Skia/Gpu/ISkiaGpuRenderSession.cs

@ -22,5 +22,7 @@ namespace Avalonia.Skia
/// Scaling factor.
/// </summary>
double ScaleFactor { get; }
GRSurfaceOrigin SurfaceOrigin { get; }
}
}

4
src/Skia/Avalonia.Skia/Gpu/OpenGl/FboSkiaSurface.cs

@ -14,7 +14,7 @@ namespace Avalonia.Skia
private int _texture;
private static readonly bool[] TrueFalse = new[] { true, false };
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize)
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize, GRSurfaceOrigin surfaceOrigin)
{
_grContext = grContext;
_glContext = glContext;
@ -93,7 +93,7 @@ namespace Avalonia.Skia
var target = new GRBackendRenderTarget(pixelSize.Width, pixelSize.Height, 0, 8,
new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat()));
Surface = SKSurface.Create(_grContext, target,
GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);
surfaceOrigin, SKColorType.Rgba8888);
CanBlit = gl.BlitFramebuffer != null;
}

9
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs

@ -39,6 +39,8 @@ namespace Avalonia.Skia
_backendRenderTarget = backendRenderTarget;
_surface = surface;
_glSession = glSession;
SurfaceOrigin = glSession.IsYFlipped ? GRSurfaceOrigin.TopLeft : GRSurfaceOrigin.BottomLeft;
}
public void Dispose()
{
@ -48,6 +50,8 @@ namespace Avalonia.Skia
GrContext.Flush();
_glSession.Dispose();
}
public GRSurfaceOrigin SurfaceOrigin { get; }
public GRContext GrContext { get; }
public SKSurface SkSurface => _surface;
@ -73,10 +77,6 @@ namespace Avalonia.Skia
$"Can't create drawing context for surface with {size} size and {scaling} scaling");
}
gl.Viewport(0, 0, size.Width, size.Height);
gl.ClearStencil(0);
gl.ClearColor(0, 0, 0, 0);
gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lock (_grContext)
{
_grContext.ResetContext();
@ -89,6 +89,7 @@ namespace Avalonia.Skia
SKColorType.Rgba8888);
success = true;
return new GlGpuSession(_grContext, renderTarget, surface, glSession);
}
}

4
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -47,7 +47,7 @@ namespace Avalonia.Skia
return null;
}
public ISkiaSurface TryCreateSurface(PixelSize size)
public ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session)
{
// Only windows platform needs our FBO trickery
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@ -62,7 +62,7 @@ namespace Avalonia.Skia
return null;
try
{
var surface = new FboSkiaSurface(_grContext, _glContext, size);
var surface = new FboSkiaSurface(_grContext, _glContext, size, session?.SurfaceOrigin ?? GRSurfaceOrigin.TopLeft);
_canCreateSurfaces = true;
return surface;
}

3
src/Skia/Avalonia.Skia/Gpu/SkiaGpuRenderTarget.cs

@ -33,7 +33,8 @@ namespace Avalonia.Skia
Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor,
VisualBrushRenderer = visualBrushRenderer,
DisableTextLcdRendering = true,
Gpu = _skiaGpu
Gpu = _skiaGpu,
CurrentSession = session
};
return new DrawingContextImpl(nfo, session);

4
src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs

@ -1,4 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

6
src/Skia/Avalonia.Skia/SurfaceRenderTarget.cs

@ -51,7 +51,7 @@ namespace Avalonia.Skia
_grContext = createInfo.GrContext;
_gpu = createInfo.Gpu;
_surface = _gpu?.TryCreateSurface(PixelSize);
_surface = _gpu?.TryCreateSurface(PixelSize, createInfo.Session);
if (_surface == null)
_surface = new SkiaSurfaceWrapper(CreateSurface(createInfo.GrContext, PixelSize.Width, PixelSize.Height,
createInfo.Format));
@ -100,7 +100,7 @@ namespace Avalonia.Skia
VisualBrushRenderer = visualBrushRenderer,
DisableTextLcdRendering = _disableLcdRendering,
GrContext = _grContext,
Gpu = _gpu
Gpu = _gpu,
};
return new DrawingContextImpl(createInfo, Disposable.Create(() => Version++));
@ -218,6 +218,8 @@ namespace Avalonia.Skia
public GRContext GrContext;
public ISkiaGpu Gpu;
public ISkiaGpuRenderSession Session;
}
}
}

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

@ -238,22 +238,46 @@ namespace Avalonia.Direct2D1
width = 0;
for (var i = 0; i < glyphCount; i++)
var scale = (float)(glyphRun.FontRenderingEmSize / glyphTypeface.DesignEmHeight);
if (glyphRun.GlyphAdvances.IsEmpty)
{
for (var i = 0; i < glyphCount; i++)
{
var advance = glyphTypeface.GetGlyphAdvance(glyphRun.GlyphIndices[i]) * scale;
run.Advances[i] = advance;
width += advance;
}
}
else
{
for (var i = 0; i < glyphCount; i++)
{
var advance = (float)glyphRun.GlyphAdvances[i];
run.Advances[i] = advance;
width += advance;
}
}
if (glyphRun.GlyphOffsets.IsEmpty)
{
run.Advances[i] = (float)glyphRun.GlyphAdvances[i];
width += run.Advances[i];
return new GlyphRunImpl(run);
}
run.Offsets = new GlyphOffset[glyphCount];
for (var i = 0; i < glyphCount; i++)
{
var offset = glyphRun.GlyphOffsets[i];
var (x, y) = glyphRun.GlyphOffsets[i];
run.Offsets[i] = new GlyphOffset
{
AdvanceOffset = (float)offset.X,
AscenderOffset = (float)offset.Y
AdvanceOffset = (float)x,
AscenderOffset = (float)y
};
}

1
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -323,7 +323,6 @@ namespace Avalonia.Direct2D1.Media
/// </summary>
/// <param name="foreground">The foreground.</param>
/// <param name="glyphRun">The glyph run.</param>
/// <param name="baselineOrigin"></param>
public void DrawGlyphRun(IBrush foreground, GlyphRun glyphRun)
{
using (var brush = CreateBrush(foreground, glyphRun.Size))

160
src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs

@ -1,6 +1,6 @@
using System.Globalization;
using System;
using System.Globalization;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Media.TextFormatting.Unicode;
using Avalonia.Platform;
using Avalonia.Utilities;
@ -15,51 +15,9 @@ namespace Avalonia.Direct2D1.Media
{
using (var buffer = new Buffer())
{
buffer.ContentType = ContentType.Unicode;
FillBuffer(buffer, text);
var breakCharPosition = text.Length - 1;
var codepoint = Codepoint.ReadAt(text, breakCharPosition, out var count);
if (codepoint.IsBreakChar)
{
var breakCharCount = 1;
if (text.Length > 1)
{
var previousCodepoint = Codepoint.ReadAt(text, breakCharPosition - count, out _);
if (codepoint == '\r' && previousCodepoint == '\n'
|| codepoint == '\n' && previousCodepoint == '\r')
{
breakCharCount = 2;
}
}
if (breakCharPosition != text.Start)
{
buffer.AddUtf16(text.Buffer.Span.Slice(0, text.Length - breakCharCount));
}
var cluster = buffer.GlyphInfos.Length > 0 ?
buffer.GlyphInfos[buffer.Length - 1].Cluster + 1 :
(uint)text.Start;
switch (breakCharCount)
{
case 1:
buffer.Add('\u200C', cluster);
break;
case 2:
buffer.Add('\u200C', cluster);
buffer.Add('\u200D', cluster);
break;
}
}
else
{
buffer.AddUtf16(text.Buffer.Span);
}
buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);
buffer.GuessSegmentProperties();
@ -67,44 +25,38 @@ namespace Avalonia.Direct2D1.Media
var font = ((GlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font;
buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture);
font.Shape(buffer);
font.GetScale(out var scaleX, out _);
var textScale = fontRenderingEmSize / scaleX;
var len = buffer.Length;
var bufferLength = buffer.Length;
var info = buffer.GetGlyphInfoSpan();
var glyphInfos = buffer.GetGlyphInfoSpan();
var pos = buffer.GetGlyphPositionSpan();
var glyphPositions = buffer.GetGlyphPositionSpan();
var glyphIndices = new ushort[len];
var glyphIndices = new ushort[bufferLength];
var clusters = new ushort[len];
var clusters = new ushort[bufferLength];
var glyphAdvances = new double[len];
double[] glyphAdvances = null;
var glyphOffsets = new Vector[len];
Vector[] glyphOffsets = null;
for (var i = 0; i < len; i++)
for (var i = 0; i < bufferLength; i++)
{
glyphIndices[i] = (ushort)info[i].Codepoint;
clusters[i] = (ushort)(text.Start + info[i].Cluster);
var advanceX = pos[i].XAdvance * textScale;
// Depends on direction of layout
//var advanceY = pos[i].YAdvance * textScale;
glyphIndices[i] = (ushort)glyphInfos[i].Codepoint;
glyphAdvances[i] = advanceX;
clusters[i] = (ushort)glyphInfos[i].Cluster;
var offsetX = pos[i].XOffset * textScale;
var offsetY = pos[i].YOffset * textScale;
if (!glyphTypeface.IsFixedPitch)
{
SetAdvance(glyphPositions, i, textScale, ref glyphAdvances);
}
glyphOffsets[i] = new Vector(offsetX, offsetY);
SetOffset(glyphPositions, i, textScale, ref glyphOffsets);
}
return new GlyphRun(glyphTypeface, fontRenderingEmSize,
@ -115,5 +67,79 @@ namespace Avalonia.Direct2D1.Media
new ReadOnlySlice<ushort>(clusters));
}
}
private static void FillBuffer(Buffer buffer, ReadOnlySlice<char> text)
{
buffer.ContentType = ContentType.Unicode;
var i = 0;
while (i < text.Length)
{
var codepoint = Codepoint.ReadAt(text, i, out var count);
var cluster = (uint)(text.Start + i);
if (codepoint.IsBreakChar)
{
if (i + 1 < text.Length)
{
var nextCodepoint = Codepoint.ReadAt(text, i + 1, out _);
if (nextCodepoint == '\r' && codepoint == '\n' || nextCodepoint == '\n' && codepoint == '\r')
{
count++;
buffer.Add('\u200C', cluster);
buffer.Add('\u200D', cluster);
}
else
{
buffer.Add('\u200C', cluster);
}
}
else
{
buffer.Add('\u200C', cluster);
}
}
else
{
buffer.Add(codepoint, cluster);
}
i += count;
}
}
private static void SetOffset(ReadOnlySpan<GlyphPosition> glyphPositions, int index, double textScale,
ref Vector[] offsetBuffer)
{
var position = glyphPositions[index];
if (position.XOffset == 0 && position.YOffset == 0)
{
return;
}
offsetBuffer ??= new Vector[glyphPositions.Length];
var offsetX = position.XOffset * textScale;
var offsetY = position.YOffset * textScale;
offsetBuffer[index] = new Vector(offsetX, offsetY);
}
private static void SetAdvance(ReadOnlySpan<GlyphPosition> glyphPositions, int index, double textScale,
ref double[] advanceBuffer)
{
advanceBuffer ??= new double[glyphPositions.Length];
// Depends on direction of layout
// advanceBuffer[index] = buffer.GlyphPositions[index].YAdvance * textScale;
advanceBuffer[index] = glyphPositions[index].XAdvance * textScale;
}
}
}

4
src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs

@ -6,6 +6,6 @@ using Avalonia.Direct2D1;
[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize),
typeof(Direct2DChecker))]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Direct2D1.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]

2
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ExtrasEnableWpfProjectSetup>true</ExtrasEnableWpfProjectSetup>
<UseWpf>true</UseWpf>
<ExtrasEnableImplicitWinFormsReferences>true</ExtrasEnableImplicitWinFormsReferences>
<UseDirect3D9>true</UseDirect3D9>
<PackageId>Avalonia.Win32.Interoperability</PackageId>

3
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -6,7 +6,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<PackageReference Include="Microsoft.Windows.SDK.NET" Version="10.0.18362.3-preview" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
</Project>

18
src/Windows/Avalonia.Win32/Composition/CompositionBlurHost.cs

@ -0,0 +1,18 @@
namespace Avalonia.Win32
{
internal class CompositionBlurHost : IBlurHost
{
Windows.UI.Composition.Visual _blurVisual;
public CompositionBlurHost(Windows.UI.Composition.Visual blurVisual)
{
_blurVisual = blurVisual;
}
public void SetBlur(bool enabled)
{
_blurVisual.IsVisible = enabled;
}
}
}

143
src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs

@ -0,0 +1,143 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Windows.UI.Composition;
using Windows.UI.Composition.Interop;
using WinRT;
namespace Avalonia.Win32
{
internal class CompositionConnector
{
private Compositor _compositor;
private Windows.System.DispatcherQueueController _dispatcherQueueController;
private CompositionGraphicsDevice _graphicsDevice;
internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
{
DQTAT_COM_NONE = 0,
DQTAT_COM_ASTA = 1,
DQTAT_COM_STA = 2
};
internal enum DISPATCHERQUEUE_THREAD_TYPE
{
DQTYPE_THREAD_DEDICATED = 1,
DQTYPE_THREAD_CURRENT = 2,
};
[StructLayout(LayoutKind.Sequential)]
internal struct DispatcherQueueOptions
{
public int dwSize;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_TYPE threadType;
[MarshalAs(UnmanagedType.I4)]
public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
};
[DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController);
public CompositionConnector(EglPlatformOpenGlInterface egl)
{
EnsureDispatcherQueue();
if (_dispatcherQueueController != null)
_compositor = new Compositor();
var interop = _compositor.As<ICompositorInterop>();
var display = egl.Display as AngleWin32EglDisplay;
_graphicsDevice = interop.CreateGraphicsDevice(display.GetDirect3DDevice());
}
public ICompositionDrawingSurfaceInterop InitialiseWindowCompositionTree(IntPtr hwnd, out Windows.UI.Composition.Visual surfaceVisual, out IBlurHost blurHost)
{
var target = CreateDesktopWindowTarget(hwnd);
var surface = _graphicsDevice.CreateDrawingSurface(new Windows.Foundation.Size(0, 0),
Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized,
Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
var surfaceInterop = surface.As<ICompositionDrawingSurfaceInterop>();
var brush = _compositor.CreateSurfaceBrush(surface);
var visual = _compositor.CreateSpriteVisual();
visual.Brush = brush;
visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1, 1);
var container = _compositor.CreateContainerVisual();
target.Root = container;
var blur = CreateBlur();
blurHost = new CompositionBlurHost(blur);
container.Children.InsertAtTop(blur);
container.Children.InsertAtTop(visual);
visual.CompositeMode = CompositionCompositeMode.SourceOver;
surfaceVisual = container;
return surfaceInterop;
}
private SpriteVisual CreateBlur()
{
var blurEffect = new GaussianBlurEffect(new CompositionEffectSourceParameter("backdrop"));
var blurEffectFactory = _compositor.CreateEffectFactory(blurEffect);
var blurBrush = blurEffectFactory.CreateBrush();
var backDropBrush = _compositor.CreateBackdropBrush();
blurBrush.SetSourceParameter("backdrop", backDropBrush);
var saturateEffect = new SaturationEffect(blurEffect);
var satEffectFactory = _compositor.CreateEffectFactory(saturateEffect);
var satBrush = satEffectFactory.CreateBrush();
satBrush.SetSourceParameter("backdrop", backDropBrush);
var visual = _compositor.CreateSpriteVisual();
visual.IsVisible = false;
visual.RelativeSizeAdjustment = new System.Numerics.Vector2(1.0f, 1.0f);
visual.Brush = satBrush;
return visual;
}
private CompositionTarget CreateDesktopWindowTarget(IntPtr window)
{
var interop = _compositor.As<global::Windows.UI.Composition.Desktop.ICompositorDesktopInterop>();
interop.CreateDesktopWindowTarget(window, false, out var windowTarget);
return Windows.UI.Composition.Desktop.DesktopWindowTarget.FromAbi(windowTarget);
}
private void EnsureDispatcherQueue()
{
if (_dispatcherQueueController == null)
{
DispatcherQueueOptions options = new DispatcherQueueOptions();
options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_NONE;
options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
CreateDispatcherQueueController(options, out var queue);
_dispatcherQueueController = Windows.System.DispatcherQueueController.FromAbi(queue);
}
}
}
}

96
src/Windows/Avalonia.Win32/Composition/CompositionEglGlPlatformSurface.cs

@ -0,0 +1,96 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;
using Windows.UI.Composition.Interop;
namespace Avalonia.Win32
{
internal class CompositionEglGlPlatformSurface : EglGlPlatformSurfaceBase
{
private EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private ICompositionDrawingSurfaceInterop _surfaceInterop;
private Windows.UI.Composition.Visual _surface;
public CompositionEglGlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) : base()
{
_egl = egl;
_info = info;
}
public IBlurHost AttachToCompositionTree(CompositionConnector connector, IntPtr hwnd)
{
using (_egl.PrimaryContext.MakeCurrent())
{
_surfaceInterop = connector.InitialiseWindowCompositionTree(hwnd, out _surface, out var blurHost);
return blurHost;
}
}
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
return new CompositionRenderTarget(_egl, _surface, _surfaceInterop, _info);
}
class CompositionRenderTarget : EglPlatformSurfaceRenderTargetBase
{
private readonly EglPlatformOpenGlInterface _egl;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
private PixelSize _currentSize;
private readonly ICompositionDrawingSurfaceInterop _surfaceInterop;
private static Guid s_Iid = Guid.Parse("6f15aaf2-d208-4e89-9ab4-489535d34f9c");
private Windows.UI.Composition.Visual _compositionVisual;
public CompositionRenderTarget(EglPlatformOpenGlInterface egl,
Windows.UI.Composition.Visual compositionVisual,
ICompositionDrawingSurfaceInterop interopSurface,
IEglWindowGlPlatformSurfaceInfo info)
: base(egl)
{
_egl = egl;
_surfaceInterop = interopSurface;
_info = info;
_currentSize = info.Size;
_compositionVisual = compositionVisual;
using (_egl.PrimaryContext.MakeCurrent())
{
_surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
}
_compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
}
public override IGlPlatformSurfaceRenderingSession BeginDraw()
{
IntPtr texture;
EglSurface surface;
using (_egl.PrimaryEglContext.EnsureCurrent())
{
if (_info.Size != _currentSize)
{
_surfaceInterop.Resize(new POINT { X = _info.Size.Width, Y = _info.Size.Height });
_compositionVisual.Size = new System.Numerics.Vector2(_info.Size.Width, _info.Size.Height);
_currentSize = _info.Size;
}
var offset = new POINT();
_surfaceInterop.BeginDraw(
IntPtr.Zero,
ref s_Iid,
out texture, ref offset);
surface = (_egl.Display as AngleWin32EglDisplay).WrapDirect3D11Texture(_egl, texture, offset.X, offset.Y, _info.Size.Width, _info.Size.Height);
}
return base.BeginDraw(surface, _info, () => { _surfaceInterop.EndDraw(); Marshal.Release(texture); surface.Dispose(); }, true);
}
}
}
}

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

Loading…
Cancel
Save