diff --git a/src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs b/src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs
index 5210b0a98f..a4e8e6f0c2 100644
--- a/src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs
+++ b/src/Avalonia.SceneGraph/Rendering/DefaultRenderLoop.cs
@@ -65,24 +65,25 @@ namespace Avalonia.Rendering
///
protected void Start()
{
- _subscription = StartCore();
+ _subscription = StartCore(InternalTick);
}
///
/// Provides the implementation of starting the timer.
///
+ /// The method to call on each tick.
///
/// This can be overridden by platform implementations to use a specialized timer
/// implementation.
///
- protected virtual IDisposable StartCore()
+ protected virtual IDisposable StartCore(Action tick)
{
if (_threading == null)
{
_threading = AvaloniaLocator.Current.GetService();
}
- return _threading.StartTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), InternalTick);
+ return _threading.StartTimer(TimeSpan.FromSeconds(1.0 / FramesPerSecond), tick);
}
///
diff --git a/src/Avalonia.SceneGraph/Rendering/Renderer.cs b/src/Avalonia.SceneGraph/Rendering/Renderer.cs
index bacef30e48..121c30fecd 100644
--- a/src/Avalonia.SceneGraph/Rendering/Renderer.cs
+++ b/src/Avalonia.SceneGraph/Rendering/Renderer.cs
@@ -13,6 +13,7 @@ namespace Avalonia.Rendering
private IRenderRoot _root;
private IRenderTarget _renderTarget;
private bool _dirty;
+ private bool _rendering;
public void Attach(IRenderRoot root, IRenderLoop renderLoop)
{
@@ -35,6 +36,11 @@ namespace Avalonia.Rendering
public void Render(Rect rect)
{
+ if (_rendering)
+ {
+ return;
+ }
+
if (_renderTarget == null)
{
_renderTarget = _root.CreateRenderTarget();
@@ -42,6 +48,7 @@ namespace Avalonia.Rendering
try
{
+ _rendering = true;
_renderTarget.Render(_root);
}
catch (RenderTargetCorruptedException ex)
@@ -50,6 +57,11 @@ namespace Avalonia.Rendering
_renderTarget.Dispose();
_renderTarget = null;
}
+ finally
+ {
+ _rendering = false;
+ _dirty = false;
+ }
}
private void OnRenderLoopTick(object sender, EventArgs e)
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
index c4bb5c8a25..51ad5ce05e 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
@@ -70,6 +70,7 @@
+
diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
index ae030df49a..d115b35a23 100644
--- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
+++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
@@ -23,6 +23,8 @@ namespace Avalonia.Win32.Interop
public delegate void TimerProc(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
+ public delegate void TimeCallback(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2);
+
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
public enum Cursor
@@ -705,8 +707,6 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
-
-
[DllImport("user32.dll")]
public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
@@ -738,6 +738,12 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow);
+ [DllImport("Winmm.dll")]
+ public static extern uint timeKillEvent(uint uTimerID);
+
+ [DllImport("Winmm.dll")]
+ public static extern uint timeSetEvent(uint uDelay, uint uResolution, TimeCallback lpTimeProc, UIntPtr dwUser, uint fuEvent);
+
[DllImport("user32.dll")]
public static extern int ToUnicode(
uint virtualKeyCode,
diff --git a/src/Windows/Avalonia.Win32/RenderLoop.cs b/src/Windows/Avalonia.Win32/RenderLoop.cs
new file mode 100644
index 0000000000..7d7befcc33
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/RenderLoop.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Reactive.Disposables;
+using Avalonia.Rendering;
+using Avalonia.Win32.Interop;
+
+namespace Avalonia.Win32
+{
+ internal class RenderLoop : DefaultRenderLoop
+ {
+ private UnmanagedMethods.TimeCallback timerDelegate;
+
+ public RenderLoop(int framesPerSecond)
+ : base(framesPerSecond)
+ {
+ }
+
+ protected override IDisposable StartCore(Action tick)
+ {
+ timerDelegate = (id, uMsg, user, dw1, dw2) => tick();
+
+ var handle = UnmanagedMethods.timeSetEvent(
+ (uint)(1000 / FramesPerSecond),
+ 0,
+ timerDelegate,
+ UIntPtr.Zero,
+ 1);
+
+ return Disposable.Create(() =>
+ {
+ timerDelegate = null;
+ UnmanagedMethods.timeKillEvent(handle);
+ });
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs
index 9b65e64e00..b437100cee 100644
--- a/src/Windows/Avalonia.Win32/Win32Platform.cs
+++ b/src/Windows/Avalonia.Win32/Win32Platform.cs
@@ -66,7 +66,7 @@ namespace Avalonia.Win32
.Bind().ToConstant(WindowsMouseDevice.Instance)
.Bind().ToConstant(s_instance)
.Bind().ToConstant(s_instance)
- .Bind().ToConstant(new DefaultRenderLoop(60))
+ .Bind().ToConstant(new RenderLoop(60))
.Bind().ToSingleton()
.Bind().ToConstant(s_instance)
.Bind().ToConstant(s_instance);