Browse Source

Initial effort on Remote

pull/1105/head
Nikita Tsukanov 9 years ago
parent
commit
a2551d505b
  1. 90
      Avalonia.sln
  2. 12
      samples/RemoteTest/Program.cs
  3. 25
      samples/RemoteTest/RemoteTest.csproj
  4. 1
      src/Avalonia.Controls/Avalonia.Controls.csproj
  5. 63
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs
  6. 65
      src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs
  7. 21
      src/Avalonia.Controls/Remote/RemoteServer.cs
  8. 101
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  9. 5
      src/Avalonia.Input/Key.cs
  10. 9
      src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj
  11. 19
      src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs
  12. 35
      src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs
  13. 10
      src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs
  14. 15
      src/Avalonia.Remote.Protocol/ITransport.cs
  15. 82
      src/Avalonia.Remote.Protocol/InputMessages.cs
  16. 54
      src/Avalonia.Remote.Protocol/ViewportMessages.cs
  17. 33
      src/Avalonia.Visuals/Platform/LockedFramebuffer.cs

90
Avalonia.sln

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
VisualStudioVersion = 15.0.26730.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
@ -185,6 +185,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "s
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{E1582370-37B3-403C-917F-8209551B1634}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Remote.Protocol", "src\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj", "{D78A720C-C0C6-478B-8564-F167F9BDD01B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteTest", "samples\RemoteTest\RemoteTest.csproj", "{E2999E4A-9086-401F-898C-AEB0AD38E676}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -2514,6 +2518,86 @@ Global
{E1582370-37B3-403C-917F-8209551B1634}.Release|Mono.Build.0 = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.ActiveCfg = Release|Any CPU
{E1582370-37B3-403C-917F-8209551B1634}.Release|x86.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Mono.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.ActiveCfg = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|x86.Build.0 = Debug|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Mono.Build.0 = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.ActiveCfg = Release|Any CPU
{D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|x86.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Mono.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.ActiveCfg = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|x86.Build.0 = Debug|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Mono.Build.0 = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.ActiveCfg = Release|Any CPU
{E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2571,5 +2655,9 @@ Global
{638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E1582370-37B3-403C-917F-8209551B1634} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{E2999E4A-9086-401F-898C-AEB0AD38E676} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1E8CA5AA-707A-4C57-A682-D265A49E10C3}
EndGlobalSection
EndGlobal

12
samples/RemoteTest/Program.cs

@ -0,0 +1,12 @@
using System;
namespace RemoteTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

25
samples/RemoteTest/RemoteTest.csproj

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj" />
<ProjectReference Include="..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj" />
<ProjectReference Include="..\..\src\Avalonia.DotNetCoreRuntime\Avalonia.DotNetCoreRuntime.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup>
</Project>

1
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -36,6 +36,7 @@
<ProjectReference Include="..\Avalonia.Input\Avalonia.Input.csproj" />
<ProjectReference Include="..\Avalonia.Interactivity\Avalonia.Interactivity.csproj" />
<ProjectReference Include="..\Avalonia.Layout\Avalonia.Layout.csproj" />
<ProjectReference Include="..\Avalonia.Remote.Protocol\Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
<ProjectReference Include="..\Avalonia.Styling\Avalonia.Styling.csproj" />
</ItemGroup>

63
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Layout;
using Avalonia.Styling;
namespace Avalonia.Controls.Embedding.Offscreen
{
class OffscreenTopLevel : TopLevel, IStyleable
{
public OffscreenTopLevelImplBase Impl { get; }
public OffscreenTopLevel(OffscreenTopLevelImplBase impl) : base(impl)
{
Impl = impl;
Prepare();
}
public void Prepare()
{
EnsureInitialized();
ApplyTemplate();
LayoutManager.Instance.ExecuteInitialLayoutPass(this);
}
private void EnsureInitialized()
{
if (!this.IsInitialized)
{
var init = (ISupportInitialize)this;
init.BeginInit();
init.EndInit();
}
}
private readonly NameScope _nameScope = new NameScope();
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
public void Register(string name, object element) => _nameScope.Register(name, element);
public object Find(string name) => _nameScope.Find(name);
public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose()
{
PlatformImpl.Dispose();
}
}
}

65
src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Platform;
namespace Avalonia.Controls.Embedding.Offscreen
{
abstract class OffscreenTopLevelImplBase : ITopLevelImpl
{
private double _scaling;
private Size _clientSize;
public IInputRoot InputRoot { get; private set; }
public virtual void Dispose()
{
//No-op
}
public abstract void Invalidate(Rect rect);
public abstract IEnumerable<object> Surfaces { get; }
public Size ClientSize
{
get { return _clientSize; }
set
{
_clientSize = value;
Resized?.Invoke(value);
}
}
public double Scaling
{
get { return _scaling; }
set
{
_scaling = value;
ScalingChanged?.Invoke(value);
}
}
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot;
public virtual Point PointToClient(Point point) => point;
public Point PointToScreen(Point point)
{
throw new NotImplementedException();
}
public virtual void SetCursor(IPlatformHandle cursor)
{
}
public Action Closed { get; set; }
}
}

21
src/Avalonia.Controls/Remote/RemoteServer.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
namespace Avalonia.Controls.Remote
{
public class RemoteServer
{
private readonly IAvaloniaRemoteTransport _transport;
public RemoteServer(IAvaloniaRemoteTransport transport)
{
_transport = transport;
}
public object Content { get; set; }
}
}

101
src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls.Embedding.Offscreen;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Platform;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using Avalonia.Threading;
using PixelFormat = Avalonia.Platform.PixelFormat;
using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat;
namespace Avalonia.Controls.Remote.Server
{
class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface
{
private readonly IAvaloniaRemoteTransport _transport;
private LockedFramebuffer _framebuffer;
private object _lock = new object();
private long _lastSentFrame;
private long _lastReceivedFrame = -1;
private bool _invalidated;
private ProtocolPixelFormat[] _supportedFormats;
public RemoteServerTopLevelImpl(IAvaloniaRemoteTransport transport)
{
_transport = transport;
_transport.OnMessage += OnMessage;
}
private void OnMessage(object obj)
{
lock (_lock)
{
var lastFrame = obj as FrameReceivedMessage;
if (lastFrame != null)
{
lock (_lock)
{
_lastReceivedFrame = lastFrame.SequenceId;
}
Dispatcher.UIThread.InvokeAsync(CheckNeedsRender);
}
var supportedFormats = obj as ClientSupportedPixelFormatsMessage;
if (supportedFormats != null)
_supportedFormats = supportedFormats.Formats;
}
}
public override IEnumerable<object> Surfaces => new[] { this };
FrameMessage RenderFrame(int width, int height, Size dpi, ProtocolPixelFormat? format)
{
var fmt = format ?? ProtocolPixelFormat.Rgba8888;
var bpp = fmt == ProtocolPixelFormat.Rgb565 ? 2 : 4;
var data = new byte[width * height * bpp];
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_framebuffer = new LockedFramebuffer(handle.AddrOfPinnedObject(), width, height, width * bpp, dpi, (PixelFormat)fmt,
null);
Paint?.Invoke(new Rect(0, 0, width, height));
}
finally
{
_framebuffer = null;
handle.Free();
}
return new FrameMessage();
}
public ILockedFramebuffer Lock()
{
if (_framebuffer == null)
throw new InvalidOperationException("Paint was not requested, wait for Paint event");
return _framebuffer;
}
void CheckNeedsRender()
{
ProtocolPixelFormat[] formats;
lock (_lock)
{
if (_lastReceivedFrame != _lastSentFrame && !_invalidated)
return;
formats = _supportedFormats;
}
//var frame = RenderFrame()
}
public override void Invalidate(Rect rect)
{
_invalidated = true;
Dispatcher.UIThread.InvokeAsync(CheckNeedsRender);
}
}
}

5
src/Avalonia.Input/Key.cs

@ -1,7 +1,10 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
#if AVALONIA_REMOTE_PROTOCOL
namespace Avalonia.Remote.Protocol.Input
#else
namespace Avalonia.Input
#endif
{
/// <summary>
/// Defines the keys available on a keyboard.

9
src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework>
<DefineConstants>AVALONIA_REMOTE_PROTOCOL;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Avalonia.Input\Key.cs" />
</ItemGroup>
</Project>

19
src/Avalonia.Remote.Protocol/AvaloniaRemoteMessageGuidAttribute.cs

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
[AttributeUsage(AttributeTargets.Class)]
public class AvaloniaRemoteMessageGuidAttribute : Attribute
{
public Guid Guid { get; }
public AvaloniaRemoteMessageGuidAttribute(string guid)
{
Guid = Guid.Parse(guid);
}
}
}

35
src/Avalonia.Remote.Protocol/DefaultMessageTypeResolver.cs

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public class DefaultMessageTypeResolver : IMessageTypeResolver
{
private readonly Dictionary<Guid, Type> _guidsToTypes = new Dictionary<Guid, Type>();
private readonly Dictionary<Type, Guid> _typesToGuids = new Dictionary<Type, Guid>();
public DefaultMessageTypeResolver(params Assembly[] assemblies)
{
foreach (var asm in
(assemblies ?? new Assembly[0]).Concat(new[]
{typeof(AvaloniaRemoteMessageGuidAttribute).GetTypeInfo().Assembly}))
{
foreach (var t in asm.ExportedTypes)
{
var attr = t.GetTypeInfo().GetCustomAttribute<AvaloniaRemoteMessageGuidAttribute>();
if (attr != null)
{
_guidsToTypes[attr.Guid] = t;
_typesToGuids[t] = attr.Guid;
}
}
}
}
public Type GetByGuid(Guid id) => _guidsToTypes[id];
public Guid GetGuid(Type type) => _typesToGuids[type];
}
}

10
src/Avalonia.Remote.Protocol/IMessageTypeResolver.cs

@ -0,0 +1,10 @@
using System;
namespace Avalonia.Remote.Protocol
{
public interface IMessageTypeResolver
{
Type GetByGuid(Guid id);
Guid GetGuid(Type type);
}
}

15
src/Avalonia.Remote.Protocol/ITransport.cs

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol
{
public interface IAvaloniaRemoteTransport
{
Task Send(object data);
event Action<object> OnMessage;
event Action<Exception> OnException;
}
}

82
src/Avalonia.Remote.Protocol/InputMessages.cs

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/*
We are keeping copies of core events here, so they can be used
without referencing Avalonia itself, e. g. from projects that
are using WPF, GTK#, etc
*/
namespace Avalonia.Remote.Protocol.Input
{
/// <summary>
/// Keep this in sync with InputModifiers in the main library
/// </summary>
[Flags]
public enum InputModifiers
{
Alt,
Control,
Shift,
Windows,
LeftMouseButton,
RightMouseButton,
MiddleMouseButton
}
/// <summary>
/// Keep this in sync with InputModifiers in the main library
/// </summary>
public enum MouseButton
{
None,
Left,
Right,
Middle
}
public abstract class InputEventMessageBase
{
public InputModifiers[] Modifiers { get; set; }
}
public abstract class PointerEventMessageBase : InputEventMessageBase
{
public double X { get; set; }
public double Y { get; set; }
}
[AvaloniaRemoteMessageGuid("6228F0B9-99F2-4F62-A621-414DA2881648")]
public class PointerMovedEventMessage : PointerEventMessageBase
{
}
[AvaloniaRemoteMessageGuid("7E9E2818-F93F-411A-800E-6B1AEB11DA46")]
public class PointerPressedEventMessage : PointerEventMessageBase
{
public MouseButton Button { get; set; }
}
[AvaloniaRemoteMessageGuid("4ADC84EE-E7C8-4BCF-986C-DE3A2F78EDE4")]
public class PointerReleasedEventMessage : PointerEventMessageBase
{
public MouseButton Button { get; set; }
}
[AvaloniaRemoteMessageGuid("79301A05-F02D-4B90-BB39-472563B504AE")]
public class ScrollEventMessage : PointerEventMessageBase
{
public double DeltaX { get; set; }
public double DeltaY { get; set; }
}
[AvaloniaRemoteMessageGuid("1C3B691E-3D54-4237-BFB0-9FEA83BC1DB8")]
public class KeyEventMessage : InputEventMessageBase
{
public bool IsDown { get; set; }
public Key Key { get; set; }
}
}

54
src/Avalonia.Remote.Protocol/ViewportMessages.cs

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Remote.Protocol.Viewport
{
public enum PixelFormat
{
Rgb565,
Rgba8888,
Bgra8888
}
[AvaloniaRemoteMessageGuid("6E3C5310-E2B1-4C3D-8688-01183AA48C5B")]
public class MeasureViewportMessage
{
public double Width { get; set; }
public double Height { get; set; }
}
[AvaloniaRemoteMessageGuid("BD7A8DE6-3DB8-4A13-8583-D6D4AB189A31")]
public class ClientViewportAllocatedMessage
{
public double Width { get; set; }
public double Height { get; set; }
}
[AvaloniaRemoteMessageGuid("63481025-7016-43FE-BADC-F2FD0F88609E")]
public class ClientSupportedPixelFormatsMessage
{
public PixelFormat[] Formats { get; set; }
}
[AvaloniaRemoteMessageGuid("68014F8A-289D-4851-8D34-5367EDA7F827")]
public class FrameReceivedMessage
{
public long SequenceId { get; set; }
}
[AvaloniaRemoteMessageGuid("F58313EE-FE69-4536-819D-F52EDF201A0E")]
public class FrameMessage
{
public long SequenceId { get; set; }
public PixelFormat Format { get; set; }
public byte[] Data { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int Stride { get; set; }
}
}

33
src/Avalonia.Visuals/Platform/LockedFramebuffer.cs

@ -0,0 +1,33 @@
using System;
namespace Avalonia.Platform
{
public class LockedFramebuffer : ILockedFramebuffer
{
private readonly Action _onDispose;
public LockedFramebuffer(IntPtr address, int width, int height, int rowBytes, Vector dpi, PixelFormat format,
Action onDispose)
{
_onDispose = onDispose;
Address = address;
Width = width;
Height = height;
RowBytes = rowBytes;
Dpi = dpi;
Format = format;
}
public IntPtr Address { get; }
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }
public Vector Dpi { get; }
public PixelFormat Format { get; }
public void Dispose()
{
_onDispose?.Invoke();
}
}
}
Loading…
Cancel
Save