Browse Source

Start/stop the renderer on window show/hide.

scenegraph-after-breakage
Steven Kirk 9 years ago
parent
commit
daf59b8497
  1. 9
      src/Avalonia.Controls/Window.cs
  2. 2
      src/Avalonia.Controls/WindowBase.cs
  3. 36
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  4. 10
      src/Avalonia.Visuals/Rendering/IRenderer.cs
  5. 10
      src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs
  6. 53
      tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
  7. 50
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  8. 6
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

9
src/Avalonia.Controls/Window.cs

@ -225,8 +225,14 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public override void Hide() public override void Hide()
{ {
if (!IsVisible)
{
return;
}
using (BeginAutoSizing()) using (BeginAutoSizing())
{ {
Renderer?.Stop();
PlatformImpl?.Hide(); PlatformImpl?.Hide();
} }
@ -252,6 +258,7 @@ namespace Avalonia.Controls
using (BeginAutoSizing()) using (BeginAutoSizing())
{ {
PlatformImpl?.Show(); PlatformImpl?.Show();
Renderer?.Start();
} }
} }
@ -297,6 +304,8 @@ namespace Avalonia.Controls
var modal = PlatformImpl?.ShowDialog(); var modal = PlatformImpl?.ShowDialog();
var result = new TaskCompletionSource<TResult>(); var result = new TaskCompletionSource<TResult>();
Renderer?.Start();
Observable.FromEventPattern<EventHandler, EventArgs>( Observable.FromEventPattern<EventHandler, EventArgs>(
x => this.Closed += x, x => this.Closed += x,
x => this.Closed -= x) x => this.Closed -= x)

2
src/Avalonia.Controls/WindowBase.cs

@ -116,6 +116,7 @@ namespace Avalonia.Controls
try try
{ {
Renderer?.Stop();
PlatformImpl?.Hide(); PlatformImpl?.Hide();
IsVisible = false; IsVisible = false;
} }
@ -138,6 +139,7 @@ namespace Avalonia.Controls
IsVisible = true; IsVisible = true;
LayoutManager.Instance.ExecuteInitialLayoutPass(this); LayoutManager.Instance.ExecuteInitialLayoutPass(this);
PlatformImpl?.Show(); PlatformImpl?.Show();
Renderer?.Start();
} }
finally finally
{ {

36
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -27,6 +27,7 @@ namespace Avalonia.Rendering
private readonly RenderLayers _layers; private readonly RenderLayers _layers;
private readonly IRenderLayerFactory _layerFactory; private readonly IRenderLayerFactory _layerFactory;
private bool _running;
private Scene _scene; private Scene _scene;
private IRenderTarget _renderTarget; private IRenderTarget _renderTarget;
private DirtyVisuals _dirty; private DirtyVisuals _dirty;
@ -60,12 +61,7 @@ namespace Avalonia.Rendering
_scene = new Scene(root); _scene = new Scene(root);
_layerFactory = layerFactory ?? new DefaultRenderLayerFactory(); _layerFactory = layerFactory ?? new DefaultRenderLayerFactory();
_layers = new RenderLayers(_layerFactory); _layers = new RenderLayers(_layerFactory);
_renderLoop = renderLoop;
if (renderLoop != null)
{
_renderLoop = renderLoop;
_renderLoop.Tick += OnRenderLoopTick;
}
} }
/// <summary> /// <summary>
@ -115,13 +111,7 @@ namespace Avalonia.Rendering
/// <summary> /// <summary>
/// Disposes of the renderer and detaches from the render loop. /// Disposes of the renderer and detaches from the render loop.
/// </summary> /// </summary>
public void Dispose() public void Dispose() => Stop();
{
if (_renderLoop != null)
{
_renderLoop.Tick -= OnRenderLoopTick;
}
}
/// <inheritdoc/> /// <inheritdoc/>
public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter) 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/> /// <inheritdoc/>
Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush) Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
{ {

10
src/Avalonia.Visuals/Rendering/IRenderer.cs

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

10
src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs

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

53
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() private FuncControlTemplate<TestWindowBase> CreateTemplate()
{ {
return new FuncControlTemplate<TestWindowBase>(x => return new FuncControlTemplate<TestWindowBase>(x =>

50
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -6,6 +6,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Moq; using Moq;
using Xunit; 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() private void ClearOpenWindows()
{ {
// HACK: We really need a decent way to have "statics" that can be scoped to // HACK: We really need a decent way to have "statics" that can be scoped to

6
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@ -33,6 +33,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
layerFactory: MockLayerFactory(root).Object, layerFactory: MockLayerFactory(root).Object,
dispatcher: dispatcher.Object); dispatcher: dispatcher.Object);
target.Start();
RunFrame(loop); RunFrame(loop);
#if !NETCOREAPP1_1 // Delegate.Method is not available in netcoreapp1.1 #if !NETCOREAPP1_1 // Delegate.Method is not available in netcoreapp1.1
@ -57,6 +58,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
layerFactory: MockLayerFactory(root).Object, layerFactory: MockLayerFactory(root).Object,
dispatcher: dispatcher); dispatcher: dispatcher);
target.Start();
RunFrame(loop); RunFrame(loop);
sceneBuilder.Verify(x => x.UpdateAll(It.IsAny<Scene>())); sceneBuilder.Verify(x => x.UpdateAll(It.IsAny<Scene>()));
@ -76,6 +78,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
layerFactory: MockLayerFactory(root).Object, layerFactory: MockLayerFactory(root).Object,
dispatcher: dispatcher); dispatcher: dispatcher);
target.Start();
IgnoreFirstFrame(loop, sceneBuilder); IgnoreFirstFrame(loop, sceneBuilder);
RunFrame(loop); RunFrame(loop);
@ -111,6 +114,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
layerFactory: MockLayerFactory(root).Object, layerFactory: MockLayerFactory(root).Object,
dispatcher: dispatcher); dispatcher: dispatcher);
target.Start();
IgnoreFirstFrame(loop, sceneBuilder); IgnoreFirstFrame(loop, sceneBuilder);
target.AddDirty(border); target.AddDirty(border);
target.AddDirty(canvas); target.AddDirty(canvas);
@ -154,6 +158,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
layerFactory: layers.Object, layerFactory: layers.Object,
dispatcher: dispatcher); dispatcher: dispatcher);
target.Start();
RunFrame(loop); RunFrame(loop);
layers.Verify(x => x.CreateLayer(root, root.ClientSize, 96, 96)); layers.Verify(x => x.CreateLayer(root, root.ClientSize, 96, 96));
@ -194,6 +199,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
dispatcher: new ImmediateDispatcher()); dispatcher: new ImmediateDispatcher());
root.Renderer = target; root.Renderer = target;
target.Start();
RunFrame(loop); RunFrame(loop);
var rootContext = layerFactory.GetMockDrawingContext(root); var rootContext = layerFactory.GetMockDrawingContext(root);

Loading…
Cancel
Save