Przeglądaj źródła

Start/stop the renderer on window show/hide.

Steven Kirk 8 lat temu
rodzic
commit
daf59b8497

+ 9 - 0
src/Avalonia.Controls/Window.cs

@@ -225,8 +225,14 @@ namespace Avalonia.Controls
         /// </summary>
         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<TResult>();
 
+                Renderer?.Start();
+
                 Observable.FromEventPattern<EventHandler, EventArgs>(
                     x => this.Closed += x,
                     x => this.Closed -= x)

+ 2 - 0
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
             {

+ 23 - 13
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;
         }
 
         /// <summary>
@@ -115,13 +111,7 @@ namespace Avalonia.Rendering
         /// <summary>
         /// Disposes of the renderer and detaches from the render loop.
         /// </summary>
-        public void Dispose()
-        {
-            if (_renderLoop != null)
-            {
-                _renderLoop.Tick -= OnRenderLoopTick;
-            }
-        }
+        public void Dispose() => Stop();
 
         /// <inheritdoc/>
         public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
@@ -145,6 +135,26 @@ namespace Avalonia.Rendering
         {
         }
 
+        /// <inheritdoc/>
+        public void Start()
+        {
+            if (!_running && _renderLoop != null)
+            {
+                _renderLoop.Tick += OnRenderLoopTick;
+                _running = true;
+            }
+        }
+
+        /// <inheritdoc/>
+        public void Stop()
+        {
+            if (_running && _renderLoop != null)
+            {
+                _renderLoop.Tick -= OnRenderLoopTick;
+                _running = false;
+            }
+        }
+
         /// <inheritdoc/>
         Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
         {

+ 10 - 0
src/Avalonia.Visuals/Rendering/IRenderer.cs

@@ -48,5 +48,15 @@ namespace Avalonia.Rendering
         /// </summary>
         /// <param name="rect">The dirty rectangle.</param>
         void Paint(Rect rect);
+
+        /// <summary>
+        /// Starts the renderer.
+        /// </summary>
+        void Start();
+
+        /// <summary>
+        /// Stops the renderer.
+        /// </summary>
+        void Stop();
     }
 }

+ 10 - 0
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

@@ -148,6 +148,16 @@ namespace Avalonia.Rendering
             return HitTest(_root, p, filter);
         }
 
+        /// <inheritdoc/>
+        public void Start()
+        {
+        }
+
+        /// <inheritdoc/>
+        public void Stop()
+        {
+        }
+
         /// <inheritdoc/>
         Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
         {

+ 53 - 0
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<IRenderer>();
+
+            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<IRenderer>();
+
+            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<IRenderer>();
+            var windowImpl = new Mock<IPopupImpl>();
+            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<TestWindowBase> CreateTemplate()
         {
             return new FuncControlTemplate<TestWindowBase>(x =>

+ 50 - 0
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<IRenderer>();
+
+            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<IRenderer>();
+
+            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<IRenderer>();
+
+            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

+ 6 - 0
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<Scene>()));
@@ -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);