From 0d68d1d6ac27841aa20224a103b470d79e86f9d8 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 10 Nov 2022 17:52:11 +0600 Subject: [PATCH] Some hack to make devtools work via websocket --- samples/ControlCatalog/ControlCatalog.csproj | 1 + samples/ControlCatalog/MainWindow.xaml.cs | 1 + .../Remote/Server/RemoteServerTopLevelImpl.cs | 2 + .../Avalonia.DesignerSupport.csproj | 1 + .../webapp/src/PreviewerServerConnection.ts | 2 + .../Avalonia.Diagnostics.csproj | 1 + .../DevToolsExtensions.cs | 9 +- .../Diagnostics/DevTools.cs | 24 ++--- .../Diagnostics/ViewModels/MainViewModel.cs | 2 +- .../Views/DevToolsRemoteServer.xaml | 17 ++++ .../Views/DevToolsRemoteServer.xaml.cs | 91 +++++++++++++++++++ .../StaticResourceExtension.cs | 4 +- 12 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml create mode 100644 src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml.cs diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 2654574a3e..36aebc4d80 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -29,6 +29,7 @@ + diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs index c61296ac8f..9a9d081d13 100644 --- a/samples/ControlCatalog/MainWindow.xaml.cs +++ b/samples/ControlCatalog/MainWindow.xaml.cs @@ -49,6 +49,7 @@ namespace ControlCatalog private void InitializeComponent() { + this.AttachDevTools(new Uri("http://0.0.0.0:15001")); AvaloniaXamlLoader.Load(this); } } diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index 3bc0593813..f33c42551c 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -315,6 +315,8 @@ namespace Avalonia.Controls.Remote.Server { lock (_lock) { + if (ClientSize.Width < 1 || ClientSize.Height < 1) + return; if (_lastReceivedFrame != _lastSentFrame || !_invalidated || _supportedFormats == null) return; diff --git a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj index 0be695e0a1..63a227f18c 100644 --- a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj +++ b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts index 7f1ab84f99..681f863c1c 100644 --- a/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts +++ b/src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts @@ -52,6 +52,7 @@ export class PreviewerServerConnection { private onMessage = (msg: MessageEvent) => { if (typeof msg.data == 'string' || msg.data instanceof String) { + console.log("message: " + msg.data) const parts = msg.data.split(':'); if (parts[0] == 'frame') { this.nextFrame = { @@ -64,6 +65,7 @@ export class PreviewerServerConnection { } } } else if (msg.data instanceof ArrayBuffer) { + console.log("received frame"); const arr = new Uint8ClampedArray(msg.data, 0); const imageData = new ImageData(arr, this.nextFrame.width, this.nextFrame.height); this.conn.send('frame-received:' + this.nextFrame.sequenceId); diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj index fe694b5730..bab6580ae4 100644 --- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj +++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj @@ -12,6 +12,7 @@ + diff --git a/src/Avalonia.Diagnostics/DevToolsExtensions.cs b/src/Avalonia.Diagnostics/DevToolsExtensions.cs index 68deaf8335..4534f46d24 100644 --- a/src/Avalonia.Diagnostics/DevToolsExtensions.cs +++ b/src/Avalonia.Diagnostics/DevToolsExtensions.cs @@ -1,5 +1,7 @@ -using Avalonia.Controls; +using System; +using Avalonia.Controls; using Avalonia.Diagnostics; +using Avalonia.Diagnostics.Views; using Avalonia.Input; namespace Avalonia @@ -81,5 +83,10 @@ namespace Avalonia { DevTools.Attach(application, options); } + + public static IDisposable AttachDevTools(this TopLevel root, Uri listenUri) + { + return DevToolsRemoteServer.Start(root, listenUri); + } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs b/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs index 9029ddf2bd..1d28eaba83 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/DevTools.cs @@ -47,10 +47,10 @@ namespace Avalonia.Diagnostics } public static IDisposable Open(TopLevel root) => - Open(Application.Current,new DevToolsOptions(),root as Window); + Open(null, new DevToolsOptions(), root); public static IDisposable Open(TopLevel root, DevToolsOptions options) => - Open(Application.Current, options, root as Window); + Open(null, options, root as Window); private static void DevToolsClosed(object? sender, EventArgs e) { @@ -103,14 +103,14 @@ namespace Avalonia.Diagnostics return result; } - private static IDisposable Open(Application? application, DevToolsOptions options, Window? owner = default) + private static IDisposable Open(Application? application, DevToolsOptions options, TopLevel? owner = default) { var focussedControl = KeyboardDevice.Instance?.FocusedElement as IControl; - if (application is null) - { - throw new ArgumentNullException(nameof(application)); - } - if (s_open.TryGetValue(application, out var window)) + var target = (AvaloniaObject?)application ?? owner; + if (target == null) + throw new ArgumentNullException(); + + if (s_open.TryGetValue(target, out var window)) { window.Activate(); window.SelectedControl(focussedControl); @@ -119,17 +119,17 @@ namespace Avalonia.Diagnostics { window = new MainWindow { - Root = new Controls.Application(application), + Root = application != null ? new Controls.Application(application) : target, Width = options.Size.Width, Height = options.Size.Height, }; window.SetOptions(options); window.SelectedControl(focussedControl); window.Closed += DevToolsClosed; - s_open.Add(application, window); - if (options.ShowAsChildWindow && owner is { }) + s_open.Add(target, window); + if (options.ShowAsChildWindow && owner is Window ownerWindow) { - window.Show(owner); + window.Show(ownerWindow); } else { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index 9e8a5d8d9b..bd742f297d 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -30,7 +30,7 @@ namespace Avalonia.Diagnostics.ViewModels private IInputRoot? _pointerOverRoot; private IScreenshotHandler? _screenshotHandler; private bool _showPropertyType; - private bool _showImplementedInterfaces; + private bool _showImplementedInterfaces = true; public MainViewModel(AvaloniaObject root) { diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml new file mode 100644 index 0000000000..d6d84a3bf0 --- /dev/null +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml.cs new file mode 100644 index 0000000000..d39569da47 --- /dev/null +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/DevToolsRemoteServer.xaml.cs @@ -0,0 +1,91 @@ +using System; +using System.Reactive.Disposables; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Embedding; +using Avalonia.Controls.Remote; +using Avalonia.Controls.Remote.Server; +using Avalonia.DesignerSupport.Remote.HtmlTransport; +using Avalonia.Diagnostics.ViewModels; +using Avalonia.Markup.Xaml; +using Avalonia.Remote.Protocol; +using Avalonia.Remote.Protocol.Viewport; +using Avalonia.Styling; + +namespace Avalonia.Diagnostics.Views; + +internal class DevToolsRemoteServer : EmbeddableControlRoot, IStyleHost, IStyledElement +{ + IStyleHost? IStyleHost.StylingParent => null; + + [Obsolete("Compiler-only", true)] + public DevToolsRemoteServer() + { + + } + + public DevToolsRemoteServer(IAvaloniaRemoteTransportConnection transport) : base(new RemoteServerTopLevelImpl(transport)) + { + AvaloniaXamlLoader.Load(this); + Width = Height = 1024; + + if (Theme is null && this.FindResource(typeof(EmbeddableControlRoot)) is ControlTheme topLevelTheme) + Theme = topLevelTheme; + } + + public Type StyleKey => typeof(EmbeddableControlRoot); + + class ZeroSignal : IAvaloniaRemoteTransportConnection + { + public void Dispose() + { + + } + + public Task Send(object data) + { + return Task.CompletedTask; + } + + public void SendMessage(object message) => OnMessage?.Invoke(this, message); + + public event Action? OnMessage; + public event Action? OnException; + public void Start() + { + } + } + + public static IDisposable Start(TopLevel target, Uri listenUri) + { + var signal = new ZeroSignal(); + var transport = new HtmlWebSocketTransport(signal, listenUri); + var vm = new MainViewModel(target); + var server = new DevToolsRemoteServer(transport) + { + DataContext = vm, + Content = vm + }; + server.ClientSize = new Size(1024, 1024); + server.Prepare(); + server.Renderer.Start(); + transport.Start(); + signal.SendMessage(new ClientViewportAllocatedMessage() + { + Height = 1024, + Width = 1024, + DpiX = 96, + DpiY = 96 + }); + + DevTools.Open(server); + return Disposable.Create(() => + { + server.Renderer.Stop(); + server.Dispose(); + transport.Dispose(); + }); + + + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index f28f7bc626..c703400db0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -57,7 +57,9 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions // hack can be removed. if (previousWasControlTheme && parent is IResourceProvider hack && - hack.Owner?.GetType().FullName == "Avalonia.Diagnostics.Views.MainWindow" && + (hack.Owner?.GetType().FullName == "Avalonia.Diagnostics.Views.MainWindow" + || hack.Owner?.GetType().FullName == "Avalonia.Diagnostics.Views.DevToolsRemoteServer" + ) && hack.Owner.TryGetResource(ResourceKey, out value)) { return ColorToBrushConverter.Convert(value, targetType);