diff --git a/src/tools/Avalonia.Designer.HostApp/DetachableTransportConnection.cs b/src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs similarity index 95% rename from src/tools/Avalonia.Designer.HostApp/DetachableTransportConnection.cs rename to src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs index 9cd87a2c59..1fb10a3a7c 100644 --- a/src/tools/Avalonia.Designer.HostApp/DetachableTransportConnection.cs +++ b/src/Avalonia.DesignerSupport/Remote/DetachableTransportConnection.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Avalonia.Remote.Protocol; -namespace Avalonia.Designer.HostApp +namespace Avalonia.DesignerSupport.Remote { class DetachableTransportConnection : IAvaloniaRemoteTransportConnection { diff --git a/src/tools/Avalonia.Designer.HostApp/PreviewerWindowImpl.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs similarity index 94% rename from src/tools/Avalonia.Designer.HostApp/PreviewerWindowImpl.cs rename to src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs index 5ffaa6459a..a787c8e8e3 100644 --- a/src/tools/Avalonia.Designer.HostApp/PreviewerWindowImpl.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs @@ -7,9 +7,9 @@ using Avalonia.Remote.Protocol; using Avalonia.Remote.Protocol.Viewport; using Avalonia.Threading; -namespace Avalonia.Designer.HostApp +namespace Avalonia.DesignerSupport.Remote { - public class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl, IEmbeddableWindowImpl + class PreviewerWindowImpl : RemoteServerTopLevelImpl, IWindowImpl, IEmbeddableWindowImpl { private readonly IAvaloniaRemoteTransportConnection _transport; diff --git a/src/tools/Avalonia.Designer.HostApp/PreviewerWindowingPlatform.cs b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs similarity index 98% rename from src/tools/Avalonia.Designer.HostApp/PreviewerWindowingPlatform.cs rename to src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs index b33f871139..ca3bb2b97f 100644 --- a/src/tools/Avalonia.Designer.HostApp/PreviewerWindowingPlatform.cs +++ b/src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs @@ -7,7 +7,7 @@ using Avalonia.Platform; using Avalonia.Remote.Protocol; using Avalonia.Rendering; -namespace Avalonia.Designer.HostApp +namespace Avalonia.DesignerSupport.Remote { class PreviewerWindowingPlatform : IWindowingPlatform, IPlatformSettings { diff --git a/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs new file mode 100644 index 0000000000..ac3438d71c --- /dev/null +++ b/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using Avalonia.Controls; +using Avalonia.Controls.Shapes; +using Avalonia.DesignerSupport; +using Avalonia.Input; +using Avalonia.Remote.Protocol; +using Avalonia.Remote.Protocol.Designer; +using Avalonia.Remote.Protocol.Viewport; +using Avalonia.Threading; + +namespace Avalonia.DesignerSupport.Remote +{ + public class RemoteDesignerEntryPoint + { + private static ClientSupportedPixelFormatsMessage s_supportedPixelFormats; + private static ClientViewportAllocatedMessage s_viewportAllocatedMessage; + private static IAvaloniaRemoteTransportConnection s_transport; + class CommandLineArgs + { + public string AppPath { get; set; } + public Uri Transport { get; set; } + } + + static Exception Die(string error) + { + if (error != null) + { + Console.Error.WriteLine(error); + Console.Error.Flush(); + } + Environment.Exit(1); + return new Exception("APPEXIT"); + } + + static Exception PrintUsage() + { + Console.Error.WriteLine("Usage: --transport transport_spec app"); + Console.Error.WriteLine(); + Console.Error.WriteLine("Example: --transport tcp-bson://127.0.0.1:30243/ MyApp.exe"); + Console.Error.Flush(); + return Die(null); + } + + static CommandLineArgs ParseCommandLineArgs(string[] args) + { + var rv = new CommandLineArgs(); + Action next = null; + try + { + foreach (var arg in args) + { + if (next != null) + { + next(arg); + next = null; + } + else if (arg == "--transport") + next = a => rv.Transport = new Uri(a, UriKind.Absolute); + else if (rv.AppPath == null) + rv.AppPath = arg; + else + PrintUsage(); + + } + if (rv.AppPath == null || rv.Transport == null) + PrintUsage(); + } + catch + { + PrintUsage(); + } + return rv; + } + + static IAvaloniaRemoteTransportConnection CreateTransport(Uri transport) + { + if (transport.Scheme == "tcp-bson") + { + return new BsonTcpTransport().Connect(IPAddress.Parse(transport.Host), transport.Port).Result; + } + PrintUsage(); + return null; + } + + interface IAppInitializer + { + Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj); + } + + class AppInitializer : IAppInitializer where T : AppBuilderBase, new() + { + public Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj) + { + var builder = (AppBuilderBase) obj; + builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport)); + builder.SetupWithoutStarting(); + return builder.Instance; + } + } + + private const string BuilderMethodName = "BuildAvaloniaApp"; + + class NeverClose : ICloseable + { + public event EventHandler Closed; + } + + public static void Main(string[] cmdline) + { + var args = ParseCommandLineArgs(cmdline); + var transport = CreateTransport(args.Transport); + var asm = Assembly.LoadFile(System.IO.Path.GetFullPath(args.AppPath)); + var entryPoint = asm.EntryPoint; + if (entryPoint == null) + throw Die($"Assembly {args.AppPath} doesn't have an entry point"); + var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName, + BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + if (builderMethod == null) + throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}"); + + var appBuilder = builderMethod.Invoke(null, null); + var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType())); + var app = initializer.GetConfiguredApp(transport, appBuilder); + s_transport = transport; + transport.OnMessage += OnTransportMessage; + transport.OnException += (t, e) => Die(e.ToString()); + app.Run(new NeverClose()); + } + + + private static void RebuildPreFlight() + { + PreviewerWindowingPlatform.PreFlightMessages = new List + { + s_supportedPixelFormats, + s_viewportAllocatedMessage + }; + } + + private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.InvokeAsync(() => + { + if (obj is ClientSupportedPixelFormatsMessage formats) + { + s_supportedPixelFormats = formats; + RebuildPreFlight(); + } + if (obj is ClientViewportAllocatedMessage viewport) + { + s_viewportAllocatedMessage = viewport; + RebuildPreFlight(); + } + if (obj is UpdateXamlMessage xaml) + { + try + { + DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath); + s_transport.Send(new UpdateXamlResultMessage()); + } + catch (Exception e) + { + s_transport.Send(new UpdateXamlResultMessage + { + Error = e.ToString() + }); + } + } + }); + } +} \ No newline at end of file diff --git a/src/tools/Avalonia.Designer.HostApp/Stubs.cs b/src/Avalonia.DesignerSupport/Remote/Stubs.cs similarity index 97% rename from src/tools/Avalonia.Designer.HostApp/Stubs.cs rename to src/Avalonia.DesignerSupport/Remote/Stubs.cs index a4160e7da4..5aad114cf7 100644 --- a/src/tools/Avalonia.Designer.HostApp/Stubs.cs +++ b/src/Avalonia.DesignerSupport/Remote/Stubs.cs @@ -11,12 +11,8 @@ using Avalonia.Input.Raw; using Avalonia.Platform; using Avalonia.Rendering; -namespace Avalonia.Designer.HostApp +namespace Avalonia.DesignerSupport.Remote { - /// - /// Popups are no-op - /// - class WindowStub : IPopupImpl, IWindowImpl { public Action Deactivated { get; set; } diff --git a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj index f0f3b12cc5..2a68862f18 100644 --- a/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj +++ b/src/tools/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj @@ -4,7 +4,6 @@ netcoreapp2.0 - diff --git a/src/tools/Avalonia.Designer.HostApp/Program.cs b/src/tools/Avalonia.Designer.HostApp/Program.cs index 88dadf479e..29640ffc6f 100644 --- a/src/tools/Avalonia.Designer.HostApp/Program.cs +++ b/src/tools/Avalonia.Designer.HostApp/Program.cs @@ -1,173 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Reflection; -using Avalonia.Controls; -using Avalonia.Controls.Shapes; -using Avalonia.DesignerSupport; -using Avalonia.Input; -using Avalonia.Remote.Protocol; -using Avalonia.Remote.Protocol.Designer; -using Avalonia.Remote.Protocol.Viewport; -using Avalonia.Threading; + namespace Avalonia.Designer.HostApp { class Program { - - private static ClientSupportedPixelFormatsMessage s_supportedPixelFormats; - private static ClientViewportAllocatedMessage s_viewportAllocatedMessage; - private static IAvaloniaRemoteTransportConnection s_transport; - class CommandLineArgs - { - public string AppPath { get; set; } - public Uri Transport { get; set; } - } - - static Exception Die(string error) - { - if (error != null) - { - Console.Error.WriteLine(error); - Console.Error.Flush(); - } - Environment.Exit(1); - return new Exception("APPEXIT"); - } - - static Exception PrintUsage() - { - Console.Error.WriteLine("Usage: --transport transport_spec app"); - Console.Error.WriteLine(); - Console.Error.WriteLine("Example: --transport tcp-bson://127.0.0.1:30243/ MyApp.exe"); - Console.Error.Flush(); - return Die(null); - } - - static CommandLineArgs ParseCommandLineArgs(string[] args) - { - var rv = new CommandLineArgs(); - Action next = null; - try - { - foreach (var arg in args) - { - if (next != null) - { - next(arg); - next = null; - } - else if (arg == "--transport") - next = a => rv.Transport = new Uri(a, UriKind.Absolute); - else if (rv.AppPath == null) - rv.AppPath = arg; - else - PrintUsage(); - - } - if (rv.AppPath == null || rv.Transport == null) - PrintUsage(); - } - catch - { - PrintUsage(); - } - return rv; - } - - static IAvaloniaRemoteTransportConnection CreateTransport(Uri transport) - { - if (transport.Scheme == "tcp-bson") - { - return new BsonTcpTransport().Connect(IPAddress.Parse(transport.Host), transport.Port).Result; - } - PrintUsage(); - return null; - } - - interface IAppInitializer - { - Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj); - } - - class AppInitializer : IAppInitializer where T : AppBuilderBase, new() - { - public Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport, object obj) - { - var builder = (AppBuilderBase) obj; - builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport)); - builder.SetupWithoutStarting(); - return builder.Instance; - } - } - - private const string BuilderMethodName = "BuildAvaloniaApp"; - - class NeverClose : ICloseable - { - public event EventHandler Closed; - } - - static void Main(string[] cmdline) - { - var args = ParseCommandLineArgs(cmdline); - var transport = CreateTransport(args.Transport); - var asm = Assembly.LoadFile(System.IO.Path.GetFullPath(args.AppPath)); - var entryPoint = asm.EntryPoint; - if (entryPoint == null) - throw Die($"Assembly {args.AppPath} doesn't have an entry point"); - var builderMethod = entryPoint.DeclaringType.GetMethod(BuilderMethodName, - BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - if (builderMethod == null) - throw Die($"{entryPoint.DeclaringType.FullName} doesn't have a method named {BuilderMethodName}"); - - var appBuilder = builderMethod.Invoke(null, null); - var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType())); - var app = initializer.GetConfiguredApp(transport, appBuilder); - s_transport = transport; - transport.OnMessage += OnTransportMessage; - transport.OnException += (t, e) => Die(e.ToString()); - app.Run(new NeverClose()); - } - - - private static void RebuildPreFlight() - { - PreviewerWindowingPlatform.PreFlightMessages = new List - { - s_supportedPixelFormats, - s_viewportAllocatedMessage - }; - } - - private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.InvokeAsync(() => - { - if (obj is ClientSupportedPixelFormatsMessage formats) - { - s_supportedPixelFormats = formats; - RebuildPreFlight(); - } - if (obj is ClientViewportAllocatedMessage viewport) - { - s_viewportAllocatedMessage = viewport; - RebuildPreFlight(); - } - if (obj is UpdateXamlMessage xaml) - { - try - { - DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath); - s_transport.Send(new UpdateXamlResultMessage()); - } - catch (Exception e) - { - s_transport.Send(new UpdateXamlResultMessage - { - Error = e.ToString() - }); - } - } - }); + public static void Main(string[] args) + => Avalonia.DesignerSupport.Remote.RemoteDesignerEntryPoint.Main(args); } } \ No newline at end of file