using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; namespace Avalonia.Controls.Platform { public class InternalPlatformThreadingInterface : IPlatformThreadingInterface { public InternalPlatformThreadingInterface() { TlsCurrentThreadIsLoopThread = true; } private readonly AutoResetEvent _signaled = new AutoResetEvent(false); public void RunLoop(CancellationToken cancellationToken) { var handles = new[] { _signaled, cancellationToken.WaitHandle }; while (!cancellationToken.IsCancellationRequested) { Signaled?.Invoke(null); WaitHandle.WaitAny(handles); } } class TimerImpl : IDisposable { private readonly DispatcherPriority _priority; private readonly TimeSpan _interval; private readonly Action _tick; private Timer _timer; private GCHandle _handle; public TimerImpl(DispatcherPriority priority, TimeSpan interval, Action tick) { _priority = priority; _interval = interval; _tick = tick; _timer = new Timer(OnTimer, null, interval, TimeSpan.FromMilliseconds(-1)); _handle = GCHandle.Alloc(_timer); } private void OnTimer(object state) { if (_timer == null) return; Dispatcher.UIThread.Post(() => { if (_timer == null) return; _tick(); _timer?.Change(_interval, TimeSpan.FromMilliseconds(-1)); }); } public void Dispose() { _handle.Free(); _timer.Dispose(); _timer = null; } } public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) { return new TimerImpl(priority, interval, tick); } public void Signal(DispatcherPriority prio) { _signaled.Set(); } [ThreadStatic] private static bool TlsCurrentThreadIsLoopThread; public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread; public event Action Signaled; #pragma warning disable CS0067 public event Action Tick; #pragma warning restore CS0067 } }