diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 3802f2b6ea..46c625cc4c 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -225,8 +225,14 @@ namespace Avalonia.Controls /// public override void Hide() { + if (!IsVisible) + { + return; + } + using (BeginAutoSizing()) { + Renderer?.Stop(); PlatformImpl?.Hide(); } @@ -252,6 +258,7 @@ namespace Avalonia.Controls using (BeginAutoSizing()) { PlatformImpl?.Show(); + Renderer?.Start(); } } @@ -297,6 +304,8 @@ namespace Avalonia.Controls var modal = PlatformImpl?.ShowDialog(); var result = new TaskCompletionSource(); + Renderer?.Start(); + Observable.FromEventPattern( x => this.Closed += x, x => this.Closed -= x) diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index 1f484fd6cb..3c2a8013de 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -116,6 +116,7 @@ namespace Avalonia.Controls try { + Renderer?.Stop(); PlatformImpl?.Hide(); IsVisible = false; } @@ -138,6 +139,7 @@ namespace Avalonia.Controls IsVisible = true; LayoutManager.Instance.ExecuteInitialLayoutPass(this); PlatformImpl?.Show(); + Renderer?.Start(); } finally { diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 051b2177be..9976bc179e 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -27,6 +27,7 @@ namespace Avalonia.Rendering private readonly RenderLayers _layers; private readonly IRenderLayerFactory _layerFactory; + private bool _running; private Scene _scene; private IRenderTarget _renderTarget; private DirtyVisuals _dirty; @@ -60,12 +61,7 @@ namespace Avalonia.Rendering _scene = new Scene(root); _layerFactory = layerFactory ?? new DefaultRenderLayerFactory(); _layers = new RenderLayers(_layerFactory); - - if (renderLoop != null) - { - _renderLoop = renderLoop; - _renderLoop.Tick += OnRenderLoopTick; - } + _renderLoop = renderLoop; } /// @@ -115,13 +111,7 @@ namespace Avalonia.Rendering /// /// Disposes of the renderer and detaches from the render loop. /// - public void Dispose() - { - if (_renderLoop != null) - { - _renderLoop.Tick -= OnRenderLoopTick; - } - } + public void Dispose() => Stop(); /// public IEnumerable HitTest(Point p, Func filter) @@ -145,6 +135,26 @@ namespace Avalonia.Rendering { } + /// + public void Start() + { + if (!_running && _renderLoop != null) + { + _renderLoop.Tick += OnRenderLoopTick; + _running = true; + } + } + + /// + public void Stop() + { + if (_running && _renderLoop != null) + { + _renderLoop.Tick -= OnRenderLoopTick; + _running = false; + } + } + /// Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) { diff --git a/src/Avalonia.Visuals/Rendering/IRenderer.cs b/src/Avalonia.Visuals/Rendering/IRenderer.cs index 8d2fc3a0c1..aa2413bdfb 100644 --- a/src/Avalonia.Visuals/Rendering/IRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/IRenderer.cs @@ -48,5 +48,15 @@ namespace Avalonia.Rendering /// /// The dirty rectangle. void Paint(Rect rect); + + /// + /// Starts the renderer. + /// + void Start(); + + /// + /// Stops the renderer. + /// + void Stop(); } } \ No newline at end of file diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 7d2222e449..4d12be7db0 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -148,6 +148,16 @@ namespace Avalonia.Rendering return HitTest(_root, p, filter); } + /// + public void Start() + { + } + + /// + public void Stop() + { + } + /// Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) { diff --git a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs index bafd4d69ef..00642b65e2 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs @@ -185,6 +185,59 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Showing_Should_Start_Renderer() + { + var renderer = new Mock(); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new TestWindowBase(); + + target.Show(); + + renderer.Verify(x => x.Start(), Times.Once); + } + } + + [Fact] + public void Hiding_Should_Stop_Renderer() + { + var renderer = new Mock(); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new TestWindowBase(); + + target.Show(); + target.Hide(); + + renderer.Verify(x => x.Stop(), Times.Once); + } + } + + [Fact] + public void Renderer_Should_Be_Disposed_When_Impl_Signals_Close() + { + var renderer = new Mock(); + var windowImpl = new Mock(); + windowImpl.Setup(x => x.Scaling).Returns(1); + windowImpl.SetupProperty(x => x.Closed); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new TestWindowBase(windowImpl.Object); + + target.Show(); + windowImpl.Object.Closed(); + + renderer.Verify(x => x.Dispose(), Times.Once); + } + } + private FuncControlTemplate CreateTemplate() { return new FuncControlTemplate(x => diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs index e0dd908bbb..276dbaafb3 100644 --- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs +++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using Avalonia.Platform; +using Avalonia.Rendering; using Avalonia.UnitTests; using Moq; using Xunit; @@ -185,6 +186,55 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Showing_Should_Start_Renderer() + { + var renderer = new Mock(); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new Window(); + + target.Show(); + + renderer.Verify(x => x.Start(), Times.Once); + } + } + + [Fact] + public void ShowDialog_Should_Start_Renderer() + { + var renderer = new Mock(); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new Window(); + + target.Show(); + + renderer.Verify(x => x.Start(), Times.Once); + } + } + + [Fact] + public void Hiding_Should_Stop_Renderer() + { + var renderer = new Mock(); + + using (UnitTestApplication.Start(TestServices.StyledWindow + .With(renderer: (root, loop) => renderer.Object))) + { + var target = new Window(); + + target.Show(); + target.Hide(); + + renderer.Verify(x => x.Stop(), Times.Once); + } + } + private void ClearOpenWindows() { // HACK: We really need a decent way to have "statics" that can be scoped to diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 675abc6246..a9b27ed601 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -33,6 +33,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering layerFactory: MockLayerFactory(root).Object, dispatcher: dispatcher.Object); + target.Start(); RunFrame(loop); #if !NETCOREAPP1_1 // Delegate.Method is not available in netcoreapp1.1 @@ -57,6 +58,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering layerFactory: MockLayerFactory(root).Object, dispatcher: dispatcher); + target.Start(); RunFrame(loop); sceneBuilder.Verify(x => x.UpdateAll(It.IsAny())); @@ -76,6 +78,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering layerFactory: MockLayerFactory(root).Object, dispatcher: dispatcher); + target.Start(); IgnoreFirstFrame(loop, sceneBuilder); RunFrame(loop); @@ -111,6 +114,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering layerFactory: MockLayerFactory(root).Object, dispatcher: dispatcher); + target.Start(); IgnoreFirstFrame(loop, sceneBuilder); target.AddDirty(border); target.AddDirty(canvas); @@ -154,6 +158,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering layerFactory: layers.Object, dispatcher: dispatcher); + target.Start(); RunFrame(loop); layers.Verify(x => x.CreateLayer(root, root.ClientSize, 96, 96)); @@ -194,6 +199,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering dispatcher: new ImmediateDispatcher()); root.Renderer = target; + target.Start(); RunFrame(loop); var rootContext = layerFactory.GetMockDrawingContext(root);