// ----------------------------------------------------------------------- // // Copyright 2014 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Win32.Threading { using System; using System.Threading; using System.Threading.Tasks; using NGenerics.DataStructures.Queues; using Perspex.Platform; using Perspex.Threading; using Splat; /// /// A main loop in a . /// internal class MainLoop { private static IPlatformThreadingInterface platform; private PriorityQueue queue = new PriorityQueue(PriorityQueueType.Maximum); /// /// Initializes static members of the class. /// static MainLoop() { platform = Locator.Current.GetService(); } /// /// Runs the main loop. /// /// /// A cancellation token used to exit the main loop. /// public void Run(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { Job job = null; while (job != null || this.queue.Count > 0) { if (job == null) { lock (this.queue) { job = this.queue.Dequeue(); } } if (job.Priority < DispatcherPriority.Input && platform.HasMessages()) { break; } try { job.Action(); job.TaskCompletionSource.SetResult(null); } catch (Exception e) { job.TaskCompletionSource.SetException(e); } job = null; } platform.ProcessMessage(); } } /// /// Invokes a method on the main loop. /// /// The method. /// The priority with which to invoke the method. /// A task that can be used to track the method's execution. public Task InvokeAsync(Action action, DispatcherPriority priority) { var job = new Job(action, priority); lock (this.queue) { this.queue.Add(job, priority); } platform.Wake(); return job.TaskCompletionSource.Task; } /// /// A job to run. /// private class Job { /// /// Initializes a new instance of the class. /// /// The method to call. /// The job priority. public Job(Action action, DispatcherPriority priority) { this.Action = action; this.Priority = priority; this.TaskCompletionSource = new TaskCompletionSource(); } /// /// Gets the method to call. /// public Action Action { get; } /// /// Gets the job priority. /// public DispatcherPriority Priority { get; } /// /// Gets the task completion source. /// public TaskCompletionSource TaskCompletionSource { get; } } } }