| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- using System;
- using System.Collections.Generic;
- using System.Net;
- using System.Reflection;
- using Avalonia.Controls;
- 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; }
- public string Method { get; set; } = Methods.AvaloniaRemote;
- public string SessionId { get; set; } = Guid.NewGuid().ToString();
- }
- static class Methods
- {
- public const string AvaloniaRemote = "avalonia-remote";
- public const string Win32 = "win32";
- }
- static Exception Die(string error)
- {
- if (error != null)
- {
- Console.Error.WriteLine(error);
- Console.Error.Flush();
- }
- Environment.Exit(1);
- return new Exception("APPEXIT");
- }
- static void Log(string message) => Console.WriteLine(message);
- static Exception PrintUsage()
- {
- Console.Error.WriteLine("Usage: --transport transport_spec --session-id sid --method method app");
- Console.Error.WriteLine();
- Console.Error.WriteLine("Example: --transport tcp-bson://127.0.0.1:30243/ --session-id 123 --method avalonia-remote MyApp.exe");
- Console.Error.Flush();
- return Die(null);
- }
-
- static CommandLineArgs ParseCommandLineArgs(string[] args)
- {
- var rv = new CommandLineArgs();
- Action<string> 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 (arg == "--method")
- next = a => rv.Method = a;
- else if (arg == "--session-id")
- next = a => rv.SessionId = a;
- 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, CommandLineArgs args, object obj);
- }
-
- class AppInitializer<T> : IAppInitializer where T : AppBuilderBase<T>, new()
- {
- public Application GetConfiguredApp(IAvaloniaRemoteTransportConnection transport,
- CommandLineArgs args, object obj)
- {
- var builder = (AppBuilderBase<T>) obj;
- if (args.Method == Methods.AvaloniaRemote)
- builder.UseWindowingSubsystem(() => PreviewerWindowingPlatform.Initialize(transport));
- if (args.Method == Methods.Win32)
- builder.UseWindowingSubsystem("Avalonia.Win32");
- builder.SetupWithoutStarting();
- return builder.Instance;
- }
- }
- private const string BuilderMethodName = "BuildAvaloniaApp";
- class NeverClose : ICloseable
- {
- public event EventHandler Closed
- {
- add {}
- remove {}
- }
- }
-
- 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}");
- Design.IsDesignMode = true;
- Log($"Obtaining AppBuilder instance from {builderMethod.DeclaringType.FullName}.{builderMethod.Name}");
- var appBuilder = builderMethod.Invoke(null, null);
- Log($"Initializing application in design mode");
- var initializer =(IAppInitializer)Activator.CreateInstance(typeof(AppInitializer<>).MakeGenericType(appBuilder.GetType()));
- var app = initializer.GetConfiguredApp(transport, args, appBuilder);
- s_transport = transport;
- transport.OnMessage += OnTransportMessage;
- transport.OnException += (t, e) => Die(e.ToString());
- Log("Sending StartDesignerSessionMessage");
- transport.Send(new StartDesignerSessionMessage {SessionId = args.SessionId});
- app.Run(new NeverClose());
- }
- private static void RebuildPreFlight()
- {
- PreviewerWindowingPlatform.PreFlightMessages = new List<object>
- {
- s_supportedPixelFormats,
- s_viewportAllocatedMessage
- };
- }
- private static Window s_currentWindow;
- private static void OnTransportMessage(IAvaloniaRemoteTransportConnection transport, object obj) => Dispatcher.UIThread.Post(() =>
- {
- if (obj is ClientSupportedPixelFormatsMessage formats)
- {
- s_supportedPixelFormats = formats;
- RebuildPreFlight();
- }
- if (obj is ClientViewportAllocatedMessage viewport)
- {
- s_viewportAllocatedMessage = viewport;
- RebuildPreFlight();
- }
- if (obj is UpdateXamlMessage xaml)
- {
- try
- {
- s_currentWindow?.Close();
- }
- catch
- {
- //Ignore
- }
- s_currentWindow = null;
- try
- {
- var dpi = s_viewportAllocatedMessage != null ? new Vector(s_viewportAllocatedMessage.DpiX, s_viewportAllocatedMessage.DpiY) : new Vector(96, 96);
- s_currentWindow = DesignWindowLoader.LoadDesignerWindow(xaml.Xaml, xaml.AssemblyPath, dpi);
- s_transport.Send(new UpdateXamlResultMessage(){Handle = s_currentWindow.PlatformImpl?.Handle?.Handle.ToString()});
- }
- catch (Exception e)
- {
- s_transport.Send(new UpdateXamlResultMessage
- {
- Error = e.ToString()
- });
- }
- }
- });
- }
- }
|