using System; using System.Collections.Generic; using System.Threading; using JetBrains.Collections.Viewable; using JetBrains.Diagnostics; using UnityEditor; namespace JetBrains.Rider.Unity.Editor { internal class MainThreadDispatcher : IScheduler { private static Thread ourUIThread; internal static readonly MainThreadDispatcher Instance = new MainThreadDispatcher(); /// /// The queue of tasks that are being requested for the next time DispatchTasks is called /// private readonly Queue myTaskQueue = new Queue(); private MainThreadDispatcher() { PluginEntryPoint.AppDomainLifetime.Bracket(() => EditorApplication.update += DispatchTasks, () => EditorApplication.update -= DispatchTasks); } /// /// Dispatches the specified action delegate. /// /// Action being requested public void Queue(Action action) { if (Thread.CurrentThread == ourUIThread) { action(); return; } lock (myTaskQueue) { myTaskQueue.Enqueue(action); } } /// /// Dispatches the tasks that has been requested since the last call to this function /// private void DispatchTasks() { ourUIThread = Thread.CurrentThread; if (myTaskQueue.Count == 0) return; while (true) { try { if (myTaskQueue.Count == 0) return; var task = myTaskQueue.Dequeue(); task(); } catch (Exception e) { Log.GetLog().Error(e); } } } public static void AssertThread() { Assertion.Require(ourUIThread == null || ourUIThread == Thread.CurrentThread, "Not a UI thread"); } /// /// Indicates whether there are tasks available for dispatching /// /// /// true if there are tasks available for dispatching; otherwise, false. /// public bool IsActive => ourUIThread == null || ourUIThread == Thread.CurrentThread; public bool OutOfOrderExecution => false; } }