Browse Source

Merge branch 'master' into maxkatz6-patch-1

pull/11579/head
Dan Walmsley 3 years ago
committed by GitHub
parent
commit
3973c11c63
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      Avalonia.sln
  2. 6
      dirs.proj
  3. 6
      nukebuild/_build.csproj
  4. 7
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  5. 11
      samples/ControlCatalog.Desktop/Program.cs
  6. 4
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs
  7. 23
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs
  8. 33
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml
  9. 52
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs
  10. 9
      samples/interop/WindowsInteropTest/Program.cs
  11. 76
      samples/interop/WindowsInteropTest/SelectorForm.Designer.cs
  12. 30
      samples/interop/WindowsInteropTest/SelectorForm.cs
  13. 120
      samples/interop/WindowsInteropTest/SelectorForm.resx
  14. 6
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  15. 2
      src/Avalonia.Controls/TopLevel.cs
  16. 1
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  17. 75
      src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs
  18. 35
      src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs
  19. 202
      src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs
  20. 55
      src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs
  21. 110
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs
  22. 12
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs
  23. 40
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs
  24. 254
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  25. 67
      src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs
  26. 10
      src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj
  27. 116
      src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs
  28. 2
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  29. 2
      src/tools/Avalonia.Designer.HostApp/Program.cs
  30. 9
      tests/Avalonia.UnitTests/InvariantCultureFixture.cs

3
Avalonia.sln

@ -135,7 +135,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Win32.Interoperability", "src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.Skia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject
@ -251,6 +251,7 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Generators.Sandbox", "samples\Generators.Sandbox\Generators.Sandbox.csproj", "{A82AD1BC-EBE6-4FC3-A13B-D52A50297533}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppWithoutLifetime", "samples\AppWithoutLifetime\AppWithoutLifetime.csproj", "{F8928267-688E-4A51-989C-612A72446D33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo", "samples\SafeAreaDemo\SafeAreaDemo.csproj", "{6B60A970-D5D2-49C2-8BAB-F9C7973B74B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SafeAreaDemo.Android", "samples\SafeAreaDemo.Android\SafeAreaDemo.Android.csproj", "{22E3BC08-EAF7-4889-BDC4-B4D3046C4E2D}"

6
dirs.proj

@ -14,11 +14,11 @@
<ProjectReference Remove="samples/*.Android/*.csproj" />
<ProjectReference Remove="samples/*.Browser/*.csproj" />
<ProjectReference Remove="samples/*.Blazor/*.csproj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows'))">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj" />
<ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup>
<!-- Build android and iOS projects only on Windows, where we have installed android workload -->

6
nukebuild/_build.csproj

@ -35,6 +35,12 @@
<EmbeddedResource Include="../build/avalonia.snk"></EmbeddedResource>
<Compile Remove="il-repack\ILRepack\Application.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\dirs.proj">
<Link>dirs.proj</Link>
</Content>
</ItemGroup>

7
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -4,10 +4,17 @@
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>../ControlCatalog.NetCore/app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\ControlCatalog.NetCore\NativeControls\Win\*.cs" Link="NativeControls\*" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />

11
samples/ControlCatalog.Desktop/Program.cs

@ -3,6 +3,8 @@ using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
using ControlCatalog.NetCore;
using ControlCatalog.Pages;
namespace ControlCatalog
{
@ -18,6 +20,15 @@ namespace ControlCatalog
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.LogToTrace()
.AfterSetup(builder =>
{
builder.Instance!.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
{
StartupScreenIndex = 1,
});
EmbedSample.Implementation = new EmbedSampleWin();
})
.UsePlatformDetect();
private static void ConfigureAssetAssembly(AppBuilder builder)

4
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs

@ -1,4 +1,4 @@
using Avalonia.Win32.Embedding;
using Avalonia.Win32.Interoperability;
namespace WindowsInteropTest
{
@ -116,4 +116,4 @@ namespace WindowsInteropTest
private System.Windows.Forms.GroupBox groupBox2;
private WinFormsAvaloniaControlHost avaloniaHost;
}
}
}

23
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs

@ -1,35 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Avalonia.Controls;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using System.Windows.Forms;
using ControlCatalog;
namespace WindowsInteropTest
{
public partial class EmbedToWinFormsDemo : Form
{
private readonly IRenderer _renderer;
public EmbedToWinFormsDemo()
{
InitializeComponent();
avaloniaHost.Content = new MainView();
_renderer = ((TopLevel)avaloniaHost.Content.GetVisualRoot()).Renderer;
_renderer.Start();
}
protected override void OnClosed(EventArgs e)
{
_renderer.Stop();
base.OnClosed(e);
}
}
}

33
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml

@ -1,33 +0,0 @@
<Window x:Class="WindowsInteropTest.EmbedToWpfDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:av="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WindowsInteropTest"
xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32"
xmlns:wpf="clr-namespace:Avalonia.Win32.Interop.Wpf;assembly=Avalonia.Win32.Interop"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400">
<DockPanel>
<GroupBox DockPanel.Dock="Left" Header="WPF">
<StackPanel>
<Slider/>
<Calendar/>
</StackPanel>
</GroupBox>
<GroupBox Header="Avalonia button" DockPanel.Dock="Bottom">
<wpf:WpfAvaloniaHost >
<av:Button Content="Avalonia button"/>
</wpf:WpfAvaloniaHost>
</GroupBox>
<GroupBox Header="AvBtn" DockPanel.Dock="Right">
<wpf:WpfAvaloniaHost x:Name="RightBtn">
<av:Button Content="Avalonia button 2"/>
</wpf:WpfAvaloniaHost>
</GroupBox>
<GroupBox Header="Avalonia">
<wpf:WpfAvaloniaHost x:Name="Host"/>
</GroupBox>
</DockPanel>
</Window>

52
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs

@ -1,52 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Rendering;
using Avalonia.VisualTree;
using ControlCatalog;
using Window = System.Windows.Window;
namespace WindowsInteropTest
{
/// <summary>
/// Interaction logic for EmbedToWpfDemo.xaml
/// </summary>
public partial class EmbedToWpfDemo : Window
{
private IRenderer _renderer;
public EmbedToWpfDemo()
{
InitializeComponent();
var view = new MainView();
Host.Content = view;
var tl = (TopLevel)view.GetVisualRoot();
tl.AttachDevTools();
_renderer = tl.Renderer;
_renderer.Start();
var btn = (Avalonia.Controls.Button) RightBtn.Content;
btn.Click += delegate
{
btn.Content += "!";
};
}
protected override void OnClosed(EventArgs e)
{
_renderer.Stop();
base.OnClosed(e);
}
}
}

9
samples/interop/WindowsInteropTest/Program.cs

@ -16,14 +16,9 @@ namespace WindowsInteropTest
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
AppBuilder.Configure<App>()
.UseWin32()
.UseDirect2D1()
.With(new Win32PlatformOptions
{
UseWindowsUIComposition = false,
ShouldRenderOnUIThread = true // necessary for WPF
})
.UseSkia()
.SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
System.Windows.Forms.Application.Run(new EmbedToWinFormsDemo());
}
}
}

76
samples/interop/WindowsInteropTest/SelectorForm.Designer.cs

@ -1,76 +0,0 @@
namespace WindowsInteropTest
{
partial class SelectorForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnEmbedToWinForms = new System.Windows.Forms.Button();
this.btnEmbedToWpf = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnEmbedToWinForms
//
this.btnEmbedToWinForms.Location = new System.Drawing.Point(12, 12);
this.btnEmbedToWinForms.Name = "btnEmbedToWinForms";
this.btnEmbedToWinForms.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWinForms.TabIndex = 0;
this.btnEmbedToWinForms.Text = "Embed to WinForms";
this.btnEmbedToWinForms.UseVisualStyleBackColor = true;
this.btnEmbedToWinForms.Click += new System.EventHandler(this.btnEmbedToWinForms_Click);
//
// btnEmbedToWpf
//
this.btnEmbedToWpf.Location = new System.Drawing.Point(219, 12);
this.btnEmbedToWpf.Name = "btnEmbedToWpf";
this.btnEmbedToWpf.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWpf.TabIndex = 1;
this.btnEmbedToWpf.Text = "Embed to WPF";
this.btnEmbedToWpf.UseVisualStyleBackColor = true;
this.btnEmbedToWpf.Click += new System.EventHandler(this.btnEmbedToWpf_Click);
//
// SelectorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(432, 284);
this.Controls.Add(this.btnEmbedToWpf);
this.Controls.Add(this.btnEmbedToWinForms);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "SelectorForm";
this.Text = "Interop";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btnEmbedToWinForms;
private System.Windows.Forms.Button btnEmbedToWpf;
}
}

30
samples/interop/WindowsInteropTest/SelectorForm.cs

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsInteropTest
{
public partial class SelectorForm : Form
{
public SelectorForm()
{
InitializeComponent();
}
private void btnEmbedToWinForms_Click(object sender, EventArgs e)
{
new EmbedToWinFormsDemo().ShowDialog(this);
}
private void btnEmbedToWpf_Click(object sender, EventArgs e)
{
new EmbedToWpfDemo().ShowDialog();
}
}
}

120
samples/interop/WindowsInteropTest/SelectorForm.resx

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

6
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj" />
<ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32.Interoperability\Avalonia.Win32.Interoperability.csproj" />
<ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
</Project>

2
src/Avalonia.Controls/TopLevel.cs

@ -391,7 +391,7 @@ namespace Avalonia.Controls
/// An <see cref="IPlatformHandle"/> describing the window handle, or null if the handle
/// could not be retrieved.
/// </returns>
public IPlatformHandle? TryGetPlatformHandle() => ((IWindowBaseImpl?) PlatformImpl)?.Handle;
public IPlatformHandle? TryGetPlatformHandle() => (PlatformImpl as IWindowBaseImpl)?.Handle;
/// <summary>
/// Gets the renderer for the window.

1
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -17,6 +17,7 @@
<ItemGroup Label="InternalsVisibleTo">
<InternalsVisibleTo Include="Avalonia.Direct2D1.RenderTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Direct2D1.UnitTests, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32.Interoperability, PublicKey=$(AvaloniaPublicKey)"/>
<InternalsVisibleTo Include="Avalonia.Win32.Interop, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>

75
src/Windows/Avalonia.Win32.Interop/WinForms/WinFormsAvaloniaControlHost.cs

@ -1,75 +0,0 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Avalonia.Controls.Embedding;
using Avalonia.Input;
using Avalonia.VisualTree;
using Avalonia.Win32.Interop;
using WinFormsControl = System.Windows.Forms.Control;
namespace Avalonia.Win32.Embedding
{
[ToolboxItem(true)]
public class WinFormsAvaloniaControlHost : WinFormsControl
{
private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot();
private IntPtr WindowHandle => ((WindowImpl) _root?.PlatformImpl)?.Handle?.Handle ?? IntPtr.Zero;
public WinFormsAvaloniaControlHost()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
UnmanagedMethods.SetParent(WindowHandle, Handle);
_root.Prepare();
if (_root.IsFocused)
_root.FocusManager.ClearFocus();
_root.GotFocus += RootGotFocus;
FixPosition();
}
public Avalonia.Controls.Control Content
{
get { return (Avalonia.Controls.Control)_root.Content; }
set { _root.Content = value; }
}
protected override void Dispose(bool disposing)
{
if (disposing)
_root.Dispose();
base.Dispose(disposing);
}
private void RootGotFocus(object sender, Interactivity.RoutedEventArgs e)
{
UnmanagedMethods.SetFocus(WindowHandle);
}
protected override void OnGotFocus(EventArgs e)
{
if (_root != null)
UnmanagedMethods.SetFocus(WindowHandle);
}
void FixPosition()
{
if (_root != null && Width > 0 && Height > 0)
UnmanagedMethods.MoveWindow(WindowHandle, 0, 0, Width, Height, true);
}
protected override void OnResize(EventArgs e)
{
FixPosition();
base.OnResize(e);
}
protected override void OnPaint(PaintEventArgs e)
{
}
}
}

35
src/Windows/Avalonia.Win32.Interop/Wpf/CursorShim.cs

@ -1,35 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Windows.Input;
namespace Avalonia.Win32.Interop.Wpf
{
static class CursorShim
{
public static Cursor FromHCursor(IntPtr hcursor)
{
var field = typeof(Cursor).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(f => f.FieldType == typeof(SafeHandle));
if (field == null)
return null;
var rv = (Cursor) FormatterServices.GetUninitializedObject(typeof(Cursor));
field.SetValue(rv, new SafeHandleShim(hcursor));
return rv;
}
class SafeHandleShim : SafeHandle
{
public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false)
{
this.handle = hcursor;
}
protected override bool ReleaseHandle() => true;
public override bool IsInvalid => false;
}
}
}

202
src/Windows/Avalonia.Win32.Interop/Wpf/Direct2DImageSurface.cs

@ -1,202 +0,0 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Avalonia.Direct2D1;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.Direct3D9;
using SharpDX.DXGI;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Device = SharpDX.Direct3D11.Device;
using Format = SharpDX.DXGI.Format;
using Query = SharpDX.Direct3D11.Query;
using QueryType = SharpDX.Direct3D11.QueryType;
using RenderTarget = SharpDX.Direct2D1.RenderTarget;
using Surface = SharpDX.DXGI.Surface;
using Usage = SharpDX.Direct3D9.Usage;
namespace Avalonia.Win32.Interop.Wpf
{
class Direct2DImageSurface : IExternalDirect2DRenderTargetSurface, IDisposable
{
class SwapBuffer: IDisposable
{
private readonly Query _event;
private readonly SharpDX.Direct3D11.Resource _resource;
private readonly SharpDX.Direct3D11.Resource _sharedResource;
public SharpDX.Direct3D9.Surface Texture { get; }
public RenderTarget Target { get;}
public IntSize Size { get; }
public SwapBuffer(IntSize size, Vector dpi)
{
int width = (int) size.Width;
int height = (int) size.Height;
_event = new Query(s_dxDevice, new QueryDescription {Type = QueryType.Event});
using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
{
Width = width,
Height = height,
ArraySize = 1,
MipLevels = 1,
Format = Format.B8G8R8A8_UNorm,
Usage = ResourceUsage.Default,
SampleDescription = new SampleDescription(2, 0),
BindFlags = BindFlags.RenderTarget,
}))
using (var surface = texture.QueryInterface<Surface>())
{
_resource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
Target = new RenderTarget(Direct2D1Platform.Direct2D1Factory, surface,
new RenderTargetProperties
{
DpiX = (float) dpi.X,
DpiY = (float) dpi.Y,
MinLevel = FeatureLevel.Level_10,
PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied),
});
}
using (var texture = new Texture2D(s_dxDevice, new Texture2DDescription
{
Width = width,
Height = height,
ArraySize = 1,
MipLevels = 1,
Format = Format.B8G8R8A8_UNorm,
Usage = ResourceUsage.Default,
SampleDescription = new SampleDescription(1, 0),
BindFlags = BindFlags.RenderTarget|BindFlags.ShaderResource,
OptionFlags = ResourceOptionFlags.Shared,
}))
using (var resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
{
_sharedResource = texture.QueryInterface<SharpDX.Direct3D11.Resource>();
var handle = resource.SharedHandle;
using (var texture9 = new Texture(s_d3DDevice, texture.Description.Width,
texture.Description.Height, 1,
Usage.RenderTarget, SharpDX.Direct3D9.Format.A8R8G8B8, Pool.Default, ref handle))
Texture = texture9.GetSurfaceLevel(0);
}
Size = size;
}
public void Dispose()
{
Texture?.Dispose();
Target?.Dispose();
_resource?.Dispose();
_sharedResource?.Dispose();
_event?.Dispose();
}
public void Flush()
{
s_dxDevice.ImmediateContext.ResolveSubresource(_resource, 0, _sharedResource, 0, Format.B8G8R8A8_UNorm);
s_dxDevice.ImmediateContext.Flush();
s_dxDevice.ImmediateContext.End(_event);
s_dxDevice.ImmediateContext.GetData(_event).Dispose();
}
}
private D3DImage _image;
private SwapBuffer _backBuffer;
private readonly WpfTopLevelImpl _impl;
private static Device s_dxDevice;
private static Direct3DEx s_d3DContext;
private static DeviceEx s_d3DDevice;
private Vector _oldDpi;
[DllImport("user32.dll", SetLastError = false)]
private static extern IntPtr GetDesktopWindow();
static void EnsureDirectX()
{
if(s_d3DDevice != null)
return;
s_d3DContext = new Direct3DEx();
SharpDX.Direct3D9.PresentParameters presentparams = new SharpDX.Direct3D9.PresentParameters
{
Windowed = true,
SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard,
DeviceWindowHandle = GetDesktopWindow(),
PresentationInterval = PresentInterval.Default
};
s_dxDevice = s_dxDevice ?? AvaloniaLocator.Current.GetRequiredService<SharpDX.DXGI.Device>()
.QueryInterface<SharpDX.Direct3D11.Device>();
s_d3DDevice = new DeviceEx(s_d3DContext, 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, presentparams);
}
public Direct2DImageSurface(WpfTopLevelImpl impl)
{
_impl = impl;
}
public RenderTarget GetOrCreateRenderTarget()
{
EnsureDirectX();
var scale = _impl.GetScaling();
var size = new IntSize(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
var dpi = scale * 96;
if (_backBuffer!=null && _backBuffer.Size == size)
return _backBuffer.Target;
if (_image == null || _oldDpi.X != dpi.X || _oldDpi.Y != dpi.Y)
{
_image = new D3DImage(dpi.X, dpi.Y);
_oldDpi = dpi;
}
_impl.ImageSource = _image;
RemoveAndDispose(ref _backBuffer);
if (size == default)
{
_image.Lock();
_image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
_image.Unlock();
return null;
}
_backBuffer = new SwapBuffer(size, dpi);
return _backBuffer.Target;
}
static void RemoveAndDispose<T>(ref T d) where T : IDisposable
{
d?.Dispose();
d = default;
}
void Swap()
{
_backBuffer.Flush();
_image.Lock();
_image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _backBuffer?.Texture?.NativePointer ?? IntPtr.Zero, true);
_image.AddDirtyRect(new Int32Rect(0, 0, _image.PixelWidth, _image.PixelHeight));
_image.Unlock();
}
public void DestroyRenderTarget()
{
RemoveAndDispose(ref _backBuffer);
}
public void BeforeDrawing()
{
}
public void AfterDrawing() => Swap();
public void Dispose()
{
RemoveAndDispose(ref _backBuffer);
}
}
}

55
src/Windows/Avalonia.Win32.Interop/Wpf/IntSize.cs

@ -1,55 +0,0 @@
using System;
namespace Avalonia.Win32.Interop.Wpf
{
struct IntSize : IEquatable<IntSize>
{
public bool Equals(IntSize other)
{
return Width == other.Width && Height == other.Height;
}
public IntSize(int width, int height)
{
Width = width;
Height = height;
}
public IntSize(double width, double height) : this((int) width, (int) height)
{
}
public static implicit operator IntSize(System.Windows.Size size)
{
return new IntSize {Width = (int) size.Width, Height = (int) size.Height};
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is IntSize size && Equals(size);
}
public override int GetHashCode()
{
unchecked
{
return (Width * 397) ^ Height;
}
}
public static bool operator ==(IntSize left, IntSize right)
{
return left.Equals(right);
}
public static bool operator !=(IntSize left, IntSize right)
{
return !left.Equals(right);
}
public int Width { get; set; }
public int Height { get; set; }
}
}

110
src/Windows/Avalonia.Win32.Interop/Wpf/WpfAvaloniaHost.cs

@ -1,110 +0,0 @@
using System;
using System.Threading;
using System.Windows;
using System.Windows.Markup;
namespace Avalonia.Win32.Interop.Wpf
{
[ContentProperty("Content")]
public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild
{
private WpfTopLevelImpl _impl;
private readonly SynchronizationContext _sync;
private bool _hasChildren;
public WpfAvaloniaHost()
{
_sync = SynchronizationContext.Current;
_impl = new WpfTopLevelImpl();
_impl.ControlRoot.Prepare();
_impl.Visibility = Visibility.Visible;
SnapsToDevicePixels = true;
UseLayoutRounding = true;
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged);
}
private void OnSourceChanged(object sender, SourceChangedEventArgs e)
{
if (e.NewSource != null && !_hasChildren)
{
AddLogicalChild(_impl);
AddVisualChild(_impl);
_hasChildren = true;
}
else
{
RemoveVisualChild(_impl);
RemoveLogicalChild(_impl);
_hasChildren = false;
}
}
public object Content
{
get => _impl.ControlRoot.Content;
set => _impl.ControlRoot.Content = value;
}
//Separate class is needed to prevent accidental resurrection
class Disposer
{
private readonly WpfTopLevelImpl _impl;
public Disposer(WpfTopLevelImpl impl)
{
_impl = impl;
}
public void Callback(object state)
{
_impl.Dispose();
}
}
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
{
_impl.InvalidateMeasure();
_impl.Measure(constraint);
return _impl.DesiredSize;
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
_impl.Arrange(new System.Windows.Rect(arrangeSize));
return arrangeSize;
}
protected override int VisualChildrenCount => 1;
protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl;
~WpfAvaloniaHost()
{
if (_impl != null)
_sync.Post(new Disposer(_impl).Callback, null);
}
public void Dispose()
{
if (_impl != null)
{
RemoveVisualChild(_impl);
RemoveLogicalChild(_impl);
_impl.Dispose();
_impl = null;
GC.SuppressFinalize(this);
}
}
void IAddChild.AddChild(object value)
{
if (Content == null)
Content = value;
else
throw new InvalidOperationException();
}
void IAddChild.AddText(string text)
{
//
}
}
}

12
src/Windows/Avalonia.Win32.Interop/Wpf/WpfInteropExtensions.cs

@ -1,12 +0,0 @@
namespace Avalonia.Win32.Interop.Wpf
{
static class WpfInteropExtensions
{
public static System.Windows.Point ToWpfPoint(this Point pt) => new System.Windows.Point(pt.X, pt.Y);
public static System.Windows.Point ToWpfPoint(this PixelPoint pt) => new System.Windows.Point(pt.X, pt.Y);
public static Point ToAvaloniaPoint(this System.Windows.Point pt) => new Point(pt.X, pt.Y);
public static PixelPoint ToAvaloniaPixelPoint(this System.Windows.Point pt) => new PixelPoint((int)pt.X, (int)pt.Y);
public static System.Windows.Size ToWpfSize(this Size pt) => new System.Windows.Size(pt.Width, pt.Height);
public static Size ToAvaloniaSize(this System.Windows.Size pt) => new Size(pt.Width, pt.Height);
}
}

40
src/Windows/Avalonia.Win32.Interop/Wpf/WpfMouseDevice.cs

@ -1,40 +0,0 @@
using System;
using Avalonia.Controls.Embedding;
using Avalonia.Input;
using Avalonia.VisualTree;
namespace Avalonia.Win32.Interop.Wpf
{
class WpfMouseDevice : MouseDevice
{
private readonly WpfTopLevelImpl _impl;
public WpfMouseDevice(WpfTopLevelImpl impl) : base(new WpfMousePointer(impl))
{
_impl = impl;
}
class WpfMousePointer : Pointer
{
private readonly WpfTopLevelImpl _impl;
public WpfMousePointer(WpfTopLevelImpl impl) : base(Pointer.GetNextFreeId(), PointerType.Mouse, true)
{
_impl = impl;
}
protected override void PlatformCapture(IInputElement control)
{
if (control == null)
{
System.Windows.Input.Mouse.Capture(null);
}
else if (((control as Visual)?.GetVisualRoot() as EmbeddableControlRoot)?.PlatformImpl != _impl)
throw new ArgumentException("Visual belongs to unknown toplevel");
else
System.Windows.Input.Mouse.Capture(_impl);
}
}
}
}

254
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -1,254 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Key = Avalonia.Input.Key;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MouseButton = System.Windows.Input.MouseButton;
namespace Avalonia.Win32.Interop.Wpf
{
class WpfTopLevelImpl : FrameworkElement, ITopLevelImpl
{
private HwndSource _currentHwndSource;
private readonly HwndSourceHook _hook;
private readonly ITopLevelImpl _ttl;
private IInputRoot _inputRoot;
private readonly IEnumerable<object> _surfaces;
private readonly IMouseDevice _mouse;
private readonly IKeyboardDevice _keyboard;
private Size _finalSize;
public EmbeddableControlRoot ControlRoot { get; }
internal ImageSource ImageSource { get; set; }
public class CustomControlRoot : EmbeddableControlRoot, IEmbeddedLayoutRoot
{
public CustomControlRoot(WpfTopLevelImpl impl) : base(impl)
{
EnforceClientSize = false;
}
protected override void OnMeasureInvalidated()
{
((FrameworkElement)PlatformImpl)?.InvalidateMeasure();
}
public Size AllocatedSize => ClientSize;
}
public WpfTopLevelImpl()
{
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged);
_hook = WndProc;
_ttl = this;
_surfaces = new object[] {new WritableBitmapSurface(this), new Direct2DImageSurface(this)};
_mouse = new WpfMouseDevice(this);
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
ControlRoot = new CustomControlRoot(this);
SnapsToDevicePixels = true;
Focusable = true;
DataContextChanged += delegate
{
ControlRoot.DataContext = DataContext;
};
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if (msg == (int)UnmanagedMethods.WindowsMessage.WM_DPICHANGED)
_ttl.ScalingChanged?.Invoke(_ttl.RenderScaling);
return IntPtr.Zero;
}
private void OnSourceChanged(object sender, SourceChangedEventArgs e)
{
_currentHwndSource?.RemoveHook(_hook);
_currentHwndSource = e.NewSource as HwndSource;
_currentHwndSource?.AddHook(_hook);
_ttl.ScalingChanged?.Invoke(_ttl.RenderScaling);
}
public void Dispose()
{
_ttl.Closed?.Invoke();
foreach(var d in _surfaces.OfType<IDisposable>())
d.Dispose();
}
Size ITopLevelImpl.ClientSize => _finalSize;
Size? ITopLevelImpl.FrameSize => null;
double ITopLevelImpl.RenderScaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1;
IEnumerable<object> ITopLevelImpl.Surfaces => _surfaces;
private Size _previousSize;
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
{
_finalSize = finalSize.ToAvaloniaSize();
if (_finalSize == _previousSize)
return finalSize;
_previousSize = _finalSize;
_ttl.Resized?.Invoke(finalSize.ToAvaloniaSize(), WindowResizeReason.Unspecified);
return base.ArrangeOverride(finalSize);
}
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
{
ControlRoot.Measure(availableSize.ToAvaloniaSize());
return ControlRoot.DesiredSize.ToWpfSize();
}
protected override void OnRender(DrawingContext drawingContext)
{
if(ActualHeight == 0 || ActualWidth == 0)
return;
_ttl.Paint?.Invoke(new Rect(0, 0, ActualWidth, ActualHeight));
if (ImageSource != null)
drawingContext.DrawImage(ImageSource, new System.Windows.Rect(0, 0, ActualWidth, ActualHeight));
}
public Compositor Compositor => Win32Platform.Compositor;
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
Point ITopLevelImpl.PointToClient(PixelPoint point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint();
PixelPoint ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPixelPoint();
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke();
static RawInputModifiers GetModifiers(MouseEventArgs e)
{
var state = Keyboard.Modifiers;
var rv = default(RawInputModifiers);
if (state.HasFlag(ModifierKeys.Windows))
rv |= RawInputModifiers.Meta;
if (state.HasFlag(ModifierKeys.Alt))
rv |= RawInputModifiers.Alt;
if (state.HasFlag(ModifierKeys.Control))
rv |= RawInputModifiers.Control;
if (state.HasFlag(ModifierKeys.Shift))
rv |= RawInputModifiers.Shift;
if (e != null)
{
if (e.LeftButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.LeftMouseButton;
if (e.RightButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.RightMouseButton;
if (e.MiddleButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.MiddleMouseButton;
}
return rv;
}
void MouseEvent(RawPointerEventType type, MouseEventArgs e)
=> _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type,
e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e)));
protected override void OnMouseDown(MouseButtonEventArgs e)
{
RawPointerEventType type;
if(e.ChangedButton == MouseButton.Left)
type = RawPointerEventType.LeftButtonDown;
else if (e.ChangedButton == MouseButton.Middle)
type = RawPointerEventType.MiddleButtonDown;
else if (e.ChangedButton == MouseButton.Right)
type = RawPointerEventType.RightButtonDown;
else
return;
MouseEvent(type, e);
Focus();
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
RawPointerEventType type;
if (e.ChangedButton == MouseButton.Left)
type = RawPointerEventType.LeftButtonUp;
else if (e.ChangedButton == MouseButton.Middle)
type = RawPointerEventType.MiddleButtonUp;
else if (e.ChangedButton == MouseButton.Right)
type = RawPointerEventType.RightButtonUp;
else
return;
MouseEvent(type, e);
Focus();
}
protected override void OnMouseMove(MouseEventArgs e)
{
MouseEvent(RawPointerEventType.Move, e);
}
protected override void OnMouseWheel(MouseWheelEventArgs e) =>
_ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot,
e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers(e)));
protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, e);
protected override void OnKeyDown(KeyEventArgs e)
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, RawKeyEventType.KeyDown,
(Key) e.Key,
GetModifiers(null)));
protected override void OnKeyUp(KeyEventArgs e)
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, _inputRoot, RawKeyEventType.KeyUp,
(Key)e.Key,
GetModifiers(null)));
protected override void OnTextInput(TextCompositionEventArgs e)
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, _inputRoot, e.Text));
void ITopLevelImpl.SetCursor(ICursorImpl cursor)
{
if (cursor == null)
Cursor = Cursors.Arrow;
else if (cursor is IPlatformHandle handle)
Cursor = CursorShim.FromHCursor(handle.Handle);
}
Action<RawInputEventArgs> ITopLevelImpl.Input { get; set; } //TODO
Action<Rect> ITopLevelImpl.Paint { get; set; }
Action<Size, WindowResizeReason> ITopLevelImpl.Resized { get; set; }
Action<double> ITopLevelImpl.ScalingChanged { get; set; }
Action<WindowTransparencyLevel> ITopLevelImpl.TransparencyLevelChanged { get; set; }
Action ITopLevelImpl.Closed { get; set; }
public new Action LostFocus { get; set; }
internal Vector GetScaling()
{
var src = PresentationSource.FromVisual(this)?.CompositionTarget;
if (src == null)
return new Vector(1, 1);
return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22);
}
public IPopupImpl CreatePopup() => null;
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevel) { }
public WindowTransparencyLevel TransparencyLevel => WindowTransparencyLevel.None;
public void SetFrameThemeVariant(PlatformThemeVariant themeVariant) { }
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(1, 1, 1);
public object TryGetFeature(Type featureType) => null;
}
}

67
src/Windows/Avalonia.Win32.Interop/Wpf/WritableBitmapSurface.cs

@ -1,67 +0,0 @@
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Win32.Interop.Wpf
{
class WritableBitmapSurface : IFramebufferPlatformSurface
{
private readonly WpfTopLevelImpl _impl;
private WriteableBitmap _bitmap;
public WritableBitmapSurface(WpfTopLevelImpl impl)
{
_impl = impl;
}
public ILockedFramebuffer Lock()
{
var scale = _impl.GetScaling();
var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y);
var dpi = scale * 96;
if (_bitmap == null || _bitmap.PixelWidth != (int) size.Width || _bitmap.PixelHeight != (int) size.Height)
{
_bitmap = new WriteableBitmap((int) size.Width, (int) size.Height, dpi.X, dpi.Y,
System.Windows.Media.PixelFormats.Bgra32, null);
}
return new LockedFramebuffer(_impl, _bitmap, dpi);
}
internal class LockedFramebuffer : ILockedFramebuffer
{
private readonly WpfTopLevelImpl _impl;
private readonly WriteableBitmap _bitmap;
public LockedFramebuffer(WpfTopLevelImpl impl, WriteableBitmap bitmap, Vector dpi)
{
_impl = impl;
_bitmap = bitmap;
Dpi = dpi;
_bitmap.Lock();
}
public void Dispose()
{
_bitmap.AddDirtyRect(new Int32Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight));
_bitmap.Unlock();
/*
using (var fileStream = new FileStream("c:\\tools\\wat.png", FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(_bitmap));
encoder.Save(fileStream);
}*/
_impl.ImageSource = _bitmap;
}
public IntPtr Address => _bitmap.BackBuffer;
public PixelSize Size => new PixelSize(_bitmap.PixelWidth, _bitmap.PixelHeight);
public int RowBytes => _bitmap.BackBufferStride;
public Vector Dpi { get; }
public PixelFormat Format => PixelFormat.Bgra8888;
}
}
}

10
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj → src/Windows/Avalonia.Win32.Interoperability/Avalonia.Win32.Interoperability.csproj

@ -1,20 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<TargetFrameworks>net461;net6.0-windows</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseWpf>true</UseWpf>
<UseWindowsForms>true</UseWindowsForms>
<ExtrasEnableImplicitWinFormsReferences>true</ExtrasEnableImplicitWinFormsReferences>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<UseDirect3D9>true</UseDirect3D9>
<PackageId>Avalonia.Win32.Interoperability</PackageId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Avalonia.Win32\Avalonia.Win32.csproj" />
<ProjectReference Include="..\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
</ItemGroup>
<Import Project="..\..\..\build\SharpDX.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
<Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\TrimmingEnable.props" />
</Project>

116
src/Windows/Avalonia.Win32.Interoperability/WinForms/WinFormsAvaloniaControlHost.cs

@ -0,0 +1,116 @@
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Avalonia.Controls.Embedding;
using Avalonia.Win32.Interop;
using WinFormsControl = System.Windows.Forms.Control;
using AvControl = Avalonia.Controls.Control;
namespace Avalonia.Win32.Interoperability;
/// <summary>
/// An element that allows you to host a Avalonia control on a Windows Forms page.
/// </summary>
[ToolboxItem(true)]
public class WinFormsAvaloniaControlHost : WinFormsControl
{
private AvControl? _content;
private EmbeddableControlRoot? _root;
private IntPtr WindowHandle => _root?.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero;
/// <summary>
/// Initializes a new instance of the <see cref="WinFormsAvaloniaControlHost"/> class.
/// </summary>
public WinFormsAvaloniaControlHost()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
/// <summary>
/// Gets or sets the Avalonia control hosted by the <see cref="WinFormsAvaloniaControlHost"/> element.
/// </summary>
public AvControl? Content
{
get => _content;
set
{
if (_content != value)
{
_content = value;
if (_root is not null)
{
_root.Content = value;
}
}
}
}
/// <inheritdoc />
protected override void OnHandleCreated(EventArgs e)
{
_root = new();
_root.Content = _content;
_root.Prepare();
_root.StartRendering();
_root.GotFocus += RootGotFocus;
FixPosition();
UnmanagedMethods.SetParent(WindowHandle, Handle);
base.OnHandleCreated(e);
}
/// <inheritdoc />
protected override void OnHandleDestroyed(EventArgs e)
{
_root?.StopRendering();
_root?.Dispose();
_root = null;
base.OnHandleDestroyed(e);
}
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
if (disposing)
{
_root?.Dispose();
_root = null;
}
base.Dispose(disposing);
}
private void RootGotFocus(object? sender, Interactivity.RoutedEventArgs e)
{
UnmanagedMethods.SetFocus(WindowHandle);
}
/// <inheritdoc />
protected override void OnGotFocus(EventArgs e)
{
var handle = WindowHandle;
if (handle != default)
UnmanagedMethods.SetFocus(handle);
}
private void FixPosition()
{
var handle = WindowHandle;
if (handle != default && Width > 0 && Height > 0)
UnmanagedMethods.MoveWindow(handle, 0, 0, Width, Height, true);
}
/// <inheritdoc />
protected override void OnResize(EventArgs e)
{
FixPosition();
base.OnResize(e);
}
/// <inheritdoc />
protected override void OnPaint(PaintEventArgs e)
{
}
}

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

@ -27,7 +27,7 @@
<NoWarn>$(NoWarn);CA1416</NoWarn>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="Avalonia.Win32.Interop, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Win32.Interoperability, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.Direct2D1, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>
</Project>

2
src/tools/Avalonia.Designer.HostApp/Program.cs

@ -8,7 +8,7 @@ namespace Avalonia.Designer.HostApp
{
class Program
{
#if NET461
#if NETFRAMEWORK
private static string s_appDir;
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

9
tests/Avalonia.UnitTests/InvariantCultureFixture.cs

@ -17,22 +17,13 @@ namespace Avalonia.UnitTests
public InvariantCultureFixture()
{
#if NET461
_restore = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
#else
_restore = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
#endif
}
public void Dispose()
{
#if NET461
Thread.CurrentThread.CurrentCulture = _restore;
#else
CultureInfo.CurrentCulture = _restore;
#endif
}
}
}

Loading…
Cancel
Save