зеркало из https://github.com/AvaloniaUI/Avalonia.git
Try to respect DispatcherPriority when possible
This commit is contained in:
Родитель
c3e36e9339
Коммит
b963d68668
|
@ -12,6 +12,7 @@ using Android.Runtime;
|
|||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.Android
|
||||
{
|
||||
|
@ -78,13 +79,13 @@ namespace Avalonia.Android
|
|||
|
||||
private void EnsureInvokeOnMainThread(Action action) => _handler.Post(action);
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
EnsureInvokeOnMainThread(() => Signaled?.Invoke());
|
||||
EnsureInvokeOnMainThread(() => Signaled?.Invoke(null));
|
||||
}
|
||||
|
||||
public bool CurrentThreadIsLoopThread => Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread());
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.Platform
|
||||
{
|
||||
|
@ -21,10 +22,10 @@ namespace Avalonia.Platform
|
|||
/// <returns>An <see cref="IDisposable"/> used to stop the timer.</returns>
|
||||
IDisposable StartTimer(TimeSpan interval, Action tick);
|
||||
|
||||
void Signal();
|
||||
void Signal(DispatcherPriority priority);
|
||||
|
||||
bool CurrentThreadIsLoopThread { get; }
|
||||
|
||||
event Action Signaled;
|
||||
event Action<DispatcherPriority?> Signaled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Avalonia.Threading
|
|||
/// <inheritdoc/>
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() => d(state));
|
||||
Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -45,7 +45,7 @@ namespace Avalonia.Threading
|
|||
if (Dispatcher.UIThread.CheckAccess())
|
||||
d(state);
|
||||
else
|
||||
Dispatcher.UIThread.InvokeTaskAsync(() => d(state)).Wait();
|
||||
Dispatcher.UIThread.InvokeTaskAsync(() => d(state), DispatcherPriority.Send).Wait();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ namespace Avalonia.Threading
|
|||
public void MainLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
var platform = AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>();
|
||||
cancellationToken.Register(platform.Signal);
|
||||
cancellationToken.Register(() => platform.Signal(DispatcherPriority.Send));
|
||||
platform.RunLoop(cancellationToken);
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ namespace Avalonia.Threading
|
|||
/// </summary>
|
||||
public void RunJobs()
|
||||
{
|
||||
_jobRunner?.RunJobs();
|
||||
_jobRunner?.RunJobs(null);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
@ -9,11 +9,7 @@ namespace Avalonia.Threading
|
|||
// TODO: These are copied from WPF - many won't apply to Avalonia.
|
||||
public enum DispatcherPriority
|
||||
{
|
||||
/// <summary>
|
||||
/// The job will not be processed.
|
||||
/// </summary>
|
||||
Inactive = 0,
|
||||
|
||||
MinValue = 1,
|
||||
/// <summary>
|
||||
/// The job will be processed when the system is idle.
|
||||
/// </summary>
|
||||
|
@ -63,5 +59,6 @@ namespace Avalonia.Threading
|
|||
/// The job will be processed before other asynchronous operations.
|
||||
/// </summary>
|
||||
Send = 10,
|
||||
MaxValue = 10
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Platform;
|
||||
|
||||
|
@ -13,29 +14,45 @@ namespace Avalonia.Threading
|
|||
/// </summary>
|
||||
internal class JobRunner
|
||||
{
|
||||
private readonly Queue<Job> _queue = new Queue<Job>();
|
||||
|
||||
|
||||
private IPlatformThreadingInterface _platform;
|
||||
|
||||
private Queue<Job>[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1)
|
||||
.Select(_ => new Queue<Job>()).ToArray();
|
||||
|
||||
public JobRunner(IPlatformThreadingInterface platform)
|
||||
{
|
||||
_platform = platform;
|
||||
}
|
||||
|
||||
Job GetNextJob(DispatcherPriority minimumPriority)
|
||||
{
|
||||
for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--)
|
||||
{
|
||||
var q = _queues[c];
|
||||
lock (q)
|
||||
{
|
||||
if (q.Count > 0)
|
||||
return q.Dequeue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs continuations pushed on the loop.
|
||||
/// </summary>
|
||||
public void RunJobs()
|
||||
/// <param name="priority">Priority to execute jobs for. Pass null if platform doesn't have internal priority system</param>
|
||||
public void RunJobs(DispatcherPriority? priority)
|
||||
{
|
||||
var minimumPriority = priority ?? DispatcherPriority.MinValue;
|
||||
while (true)
|
||||
{
|
||||
Job job;
|
||||
|
||||
lock (_queue)
|
||||
{
|
||||
if (_queue.Count == 0)
|
||||
return;
|
||||
job = _queue.Dequeue();
|
||||
}
|
||||
var job = GetNextJob(minimumPriority);
|
||||
if (job == null)
|
||||
return;
|
||||
|
||||
|
||||
if (job.TaskCompletionSource == null)
|
||||
{
|
||||
|
@ -77,7 +94,6 @@ namespace Avalonia.Threading
|
|||
/// <param name="priority">The priority with which to invoke the method.</param>
|
||||
internal void Post(Action action, DispatcherPriority priority)
|
||||
{
|
||||
// TODO: Respect priority.
|
||||
AddJob(new Job(action, priority, true));
|
||||
}
|
||||
|
||||
|
@ -92,13 +108,14 @@ namespace Avalonia.Threading
|
|||
private void AddJob(Job job)
|
||||
{
|
||||
var needWake = false;
|
||||
lock (_queue)
|
||||
var queue = _queues[(int) job.Priority];
|
||||
lock (queue)
|
||||
{
|
||||
needWake = _queue.Count == 0;
|
||||
_queue.Enqueue(job);
|
||||
needWake = queue.Count == 0;
|
||||
queue.Enqueue(job);
|
||||
}
|
||||
if (needWake)
|
||||
_platform?.Signal();
|
||||
_platform?.Signal(job.Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Platform;
|
||||
|
||||
namespace Avalonia.Threading
|
||||
{
|
||||
public class SingleThreadDispatcher : Dispatcher
|
||||
{
|
||||
class ThreadingInterface : IPlatformThreadingInterface
|
||||
{
|
||||
private readonly AutoResetEvent _evnt = new AutoResetEvent(false);
|
||||
private readonly JobRunner _timerJobRunner;
|
||||
|
||||
public ThreadingInterface()
|
||||
{
|
||||
_timerJobRunner = new JobRunner(this);
|
||||
}
|
||||
|
||||
public void RunLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_evnt.WaitOne();
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
Signaled?.Invoke();
|
||||
_timerJobRunner.RunJobs();
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable StartTimer(TimeSpan interval, Action tick)
|
||||
=> AvaloniaLocator.Current.GetService<IRuntimePlatform>().StartSystemTimer(interval,
|
||||
() => _timerJobRunner.Post(tick, DispatcherPriority.Normal));
|
||||
|
||||
public void Signal() => _evnt.Set();
|
||||
//TODO: Actually perform a check
|
||||
public bool CurrentThreadIsLoopThread => true;
|
||||
|
||||
public event Action Signaled;
|
||||
}
|
||||
|
||||
public SingleThreadDispatcher() : base(new ThreadingInterface())
|
||||
{
|
||||
}
|
||||
|
||||
public static Dispatcher StartNew(CancellationToken token)
|
||||
{
|
||||
var dispatcher = new SingleThreadDispatcher();
|
||||
AvaloniaLocator.Current.GetService<IRuntimePlatform>().PostThreadPoolItem(() =>
|
||||
{
|
||||
dispatcher.MainLoop(token);
|
||||
});
|
||||
return dispatcher;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -165,7 +165,7 @@ namespace Avalonia.Controls.Primitives
|
|||
|
||||
if (increaseButton != null)
|
||||
{
|
||||
increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, remaining - firstHeight));
|
||||
increaseButton.Arrange(new Rect(0, firstHeight + thumbHeight, finalSize.Width, Math.Max(remaining - firstHeight, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ using Avalonia.Input.Platform;
|
|||
using Avalonia.Input;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia
|
||||
{
|
||||
|
@ -91,14 +92,14 @@ namespace Avalonia.Gtk
|
|||
|
||||
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
Gtk.Application.Invoke(delegate { Signaled?.Invoke(); });
|
||||
Gtk.Application.Invoke(delegate { Signaled?.Invoke(null); });
|
||||
}
|
||||
|
||||
public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread;
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
public IWindowImpl CreateWindow()
|
||||
{
|
||||
return new WindowImpl();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
|
@ -28,33 +27,6 @@
|
|||
<Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
|
||||
<Link>KeyTransform.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Interop\CairoSurface.cs" />
|
||||
<Compile Include="ClipboardImpl.cs" />
|
||||
<Compile Include="CursorFactory.cs" />
|
||||
<Compile Include="FramebufferManager.cs" />
|
||||
<Compile Include="GdkCursor.cs" />
|
||||
<Compile Include="GdkKey.cs" />
|
||||
<Compile Include="Gtk3Platform.cs" />
|
||||
<Compile Include="Interop\GException.cs" />
|
||||
<Compile Include="Interop\GObject.cs" />
|
||||
<Compile Include="Interop\ICustomGtk3NativeLibraryResolver.cs" />
|
||||
<Compile Include="Interop\DynLoader.cs" />
|
||||
<Compile Include="Interop\GlibTimeout.cs" />
|
||||
<Compile Include="Interop\Native.cs" />
|
||||
<Compile Include="Interop\NativeException.cs" />
|
||||
<Compile Include="Interop\Pixbuf.cs" />
|
||||
<Compile Include="Interop\Resolver.cs" />
|
||||
<Compile Include="Interop\Signal.cs" />
|
||||
<Compile Include="ImageSurfaceFramebuffer.cs" />
|
||||
<Compile Include="PlatformIconLoader.cs" />
|
||||
<Compile Include="PopupImpl.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SystemDialogs.cs" />
|
||||
<Compile Include="WindowBaseImpl.cs" />
|
||||
<Compile Include="Interop\Utf8Buffer.cs" />
|
||||
<Compile Include="WindowImpl.cs" />
|
||||
<Compile Include="ScreenImpl.cs" />
|
||||
<Compile Include="GtkScreen.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
|
||||
|
|
|
@ -12,6 +12,7 @@ using Avalonia.Input.Platform;
|
|||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Gtk3;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.Gtk3
|
||||
{
|
||||
|
@ -68,27 +69,28 @@ namespace Avalonia.Gtk3
|
|||
return GlibTimeout.StarTimer((uint) interval.TotalMilliseconds, tick);
|
||||
}
|
||||
|
||||
private bool _signaled = false;
|
||||
private bool[] _signaled = new bool[(int) DispatcherPriority.MaxValue + 1];
|
||||
object _lock = new object();
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
var idx = (int) prio;
|
||||
lock(_lock)
|
||||
if (!_signaled)
|
||||
if (!_signaled[idx])
|
||||
{
|
||||
_signaled = true;
|
||||
GlibTimeout.Add(0, () =>
|
||||
_signaled[idx] = true;
|
||||
GlibTimeout.Add(GlibPriority.FromDispatcherPriority(prio), 0, () =>
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_signaled = false;
|
||||
_signaled[idx] = false;
|
||||
}
|
||||
Signaled?.Invoke();
|
||||
Signaled?.Invoke(prio);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
|
||||
|
||||
[ThreadStatic]
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.Gtk3.Interop
|
||||
{
|
||||
static class GlibPriority
|
||||
{
|
||||
public static int High = -100;
|
||||
public static int Default = 0;
|
||||
public static int HighIdle = 100;
|
||||
public static int GtkResize = HighIdle + 10;
|
||||
public static int GtkPaint = HighIdle + 20;
|
||||
public static int DefaultIdle = 200;
|
||||
public static int Low = 300;
|
||||
public static int GdkEvents = Default;
|
||||
public static int GdkRedraw = HighIdle + 20;
|
||||
|
||||
public static int FromDispatcherPriority(DispatcherPriority prio)
|
||||
{
|
||||
if (prio == DispatcherPriority.Send)
|
||||
return High;
|
||||
if (prio == DispatcherPriority.Normal)
|
||||
return Default - 4;
|
||||
if (prio == DispatcherPriority.DataBind)
|
||||
return Default - 3;
|
||||
if (prio == DispatcherPriority.Render)
|
||||
return Default -2;
|
||||
if (prio == DispatcherPriority.Loaded)
|
||||
return Default - 1;
|
||||
if (prio == DispatcherPriority.Input)
|
||||
return Default;
|
||||
if (prio == DispatcherPriority.Background)
|
||||
return DefaultIdle;
|
||||
if (prio == DispatcherPriority.ContextIdle)
|
||||
return DefaultIdle + 100;
|
||||
if (prio == DispatcherPriority.ApplicationIdle)
|
||||
return DefaultIdle + 200;
|
||||
if (prio == DispatcherPriority.SystemIdle)
|
||||
return DefaultIdle + 200;
|
||||
throw new ArgumentException("Unknown priority");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ namespace Avalonia.Gtk3.Interop
|
|||
}
|
||||
|
||||
|
||||
public static void Add(uint interval, Func<bool> callback)
|
||||
public static void Add(int priority, uint interval, Func<bool> callback)
|
||||
{
|
||||
var handle = GCHandle.Alloc(callback);
|
||||
Native.GTimeoutAdd(interval, PinnedHandler, GCHandle.ToIntPtr(handle));
|
||||
|
@ -49,7 +49,7 @@ namespace Avalonia.Gtk3.Interop
|
|||
public static IDisposable StarTimer(uint interval, Action tick)
|
||||
{
|
||||
var timer = new Timer ();
|
||||
GlibTimeout.Add(interval,
|
||||
GlibTimeout.Add(101, interval,
|
||||
() =>
|
||||
{
|
||||
if (timer.Stopped)
|
||||
|
|
|
@ -236,6 +236,9 @@ namespace Avalonia.Gtk3.Interop
|
|||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
|
||||
public delegate void gdk_window_begin_resize_drag(IntPtr window, WindowEdge edge, gint button, gint root_x, gint root_y, guint32 timestamp);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
|
||||
public delegate void gdk_window_process_updates(IntPtr window, bool updateChildren);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Gdk)]
|
||||
public delegate void gdk_event_request_motions(IntPtr ev);
|
||||
|
||||
|
@ -287,7 +290,10 @@ namespace Avalonia.Gtk3.Interop
|
|||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
|
||||
public delegate ulong g_timeout_add(uint interval, timeout_callback callback, IntPtr data);
|
||||
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
|
||||
public delegate ulong g_timeout_add_full(int prio, uint interval, timeout_callback callback, IntPtr data, IntPtr destroy);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Glib)]
|
||||
public delegate ulong g_free(IntPtr data);
|
||||
|
||||
|
@ -366,6 +372,7 @@ namespace Avalonia.Gtk3.Interop
|
|||
public static D.g_signal_connect_object GSignalConnectObject;
|
||||
public static D.g_signal_handler_disconnect GSignalHandlerDisconnect;
|
||||
public static D.g_timeout_add GTimeoutAdd;
|
||||
public static D.g_timeout_add_full GTimeoutAddFull;
|
||||
public static D.g_free GFree;
|
||||
public static D.g_slist_free GSlistFree;
|
||||
public static D.g_memory_input_stream_new_from_data GMemoryInputStreamNewFromData;
|
||||
|
@ -398,6 +405,7 @@ namespace Avalonia.Gtk3.Interop
|
|||
public static D.gdk_window_begin_move_drag GdkWindowBeginMoveDrag;
|
||||
public static D.gdk_window_begin_resize_drag GdkWindowBeginResizeDrag;
|
||||
public static D.gdk_event_request_motions GdkEventRequestMotions;
|
||||
public static D.gdk_window_process_updates GdkWindowProcessUpdates;
|
||||
|
||||
public static D.gdk_pixbuf_new_from_file GdkPixbufNewFromFile;
|
||||
public static D.gtk_icon_theme_get_default GtkIconThemeGetDefault;
|
||||
|
|
|
@ -140,13 +140,11 @@ namespace Avalonia.Gtk3.Interop
|
|||
var nativeHandleNames = new[] { "gdk_win32_window_get_handle", "gdk_x11_window_get_xid", "gdk_quartz_window_get_nswindow" };
|
||||
foreach (var name in nativeHandleNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle)Marshal
|
||||
.GetDelegateForFunctionPointer(loader.GetProcAddress(dlls[GtkDll.Gdk], name, false), typeof(Native.D.gdk_get_native_handle));
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
var ptr = loader.GetProcAddress(dlls[GtkDll.Gdk], name, true);
|
||||
if (ptr == IntPtr.Zero)
|
||||
continue;
|
||||
Native.GetNativeGdkWindowHandle = (Native.D.gdk_get_native_handle) Marshal
|
||||
.GetDelegateForFunctionPointer(ptr, typeof(Native.D.gdk_get_native_handle));
|
||||
}
|
||||
if (Native.GetNativeGdkWindowHandle == null)
|
||||
throw new Exception($"Unable to locate any of [{string.Join(", ", nativeHandleNames)}] in libgdk");
|
||||
|
|
|
@ -10,6 +10,7 @@ using Avalonia.Input;
|
|||
using Avalonia.Input.Raw;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.Gtk3
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ namespace Avalonia.Gtk3
|
|||
private double _lastScaling;
|
||||
private uint _lastKbdEvent;
|
||||
private uint _lastSmoothScrollEvent;
|
||||
private bool _hasDirtyRects;
|
||||
|
||||
public WindowBaseImpl(GtkWindow gtkWidget)
|
||||
{
|
||||
|
@ -222,6 +224,7 @@ namespace Avalonia.Gtk3
|
|||
|
||||
private bool OnDraw(IntPtr gtkwidget, IntPtr cairocontext, IntPtr userdata)
|
||||
{
|
||||
_hasDirtyRects = false;
|
||||
CurrentCairoContext = cairocontext;
|
||||
Paint?.Invoke(new Rect(ClientSize));
|
||||
CurrentCairoContext = IntPtr.Zero;
|
||||
|
@ -271,6 +274,19 @@ namespace Avalonia.Gtk3
|
|||
if(GtkWidget.IsClosed)
|
||||
return;
|
||||
Native.GtkWidgetQueueDrawArea(GtkWidget, (int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
|
||||
if (!_hasDirtyRects)
|
||||
{
|
||||
_hasDirtyRects = true;
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
if (GtkWidget.IsClosed)
|
||||
return;
|
||||
var window = Native.GtkWidgetGetWindow(GtkWidget);
|
||||
if (window == IntPtr.Zero)
|
||||
return;
|
||||
Native.GdkWindowProcessUpdates(window, false);
|
||||
}, DispatcherPriority.Render);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.LinuxFramebuffer
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace Avalonia.LinuxFramebuffer
|
|||
while (true)
|
||||
{
|
||||
if (0 == WaitHandle.WaitAny(handles))
|
||||
Signaled?.Invoke();
|
||||
Signaled?.Invoke(null);
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
|
@ -97,7 +98,7 @@ namespace Avalonia.LinuxFramebuffer
|
|||
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
_signaled.Set();
|
||||
}
|
||||
|
@ -105,7 +106,7 @@ namespace Avalonia.LinuxFramebuffer
|
|||
[ThreadStatic] private static bool TlsCurrentThreadIsLoopThread;
|
||||
|
||||
public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread;
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
public event EventHandler<EventArgs> Tick;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
using MonoMac.AppKit;
|
||||
using MonoMac.CoreGraphics;
|
||||
using MonoMac.Foundation;
|
||||
|
@ -13,12 +14,12 @@ namespace Avalonia.MonoMac
|
|||
public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
|
||||
public bool CurrentThreadIsLoopThread => NSThread.Current.IsMainThread;
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
|
||||
public IDisposable StartTimer(TimeSpan interval, Action tick)
|
||||
=> NSTimer.CreateRepeatingScheduledTimer(interval, () => tick());
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace Avalonia.MonoMac
|
|||
return;
|
||||
_signaled = false;
|
||||
}
|
||||
Signaled?.Invoke();
|
||||
Signaled?.Invoke(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ using Avalonia.Win32.Input;
|
|||
using Avalonia.Win32.Interop;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Threading;
|
||||
#if NETSTANDARD
|
||||
using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
|
||||
#else
|
||||
|
@ -137,7 +138,7 @@ namespace Avalonia.Win32
|
|||
private static readonly int SignalW = unchecked((int) 0xdeadbeaf);
|
||||
private static readonly int SignalL = unchecked((int)0x12345678);
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
UnmanagedMethods.PostMessage(
|
||||
_hwnd,
|
||||
|
@ -148,14 +149,14 @@ namespace Avalonia.Win32
|
|||
|
||||
public bool CurrentThreadIsLoopThread => _uiThread == UnmanagedMethods.GetCurrentThreadId();
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
|
||||
[SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Using Win32 naming for consistency.")]
|
||||
private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (msg == (int) UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM && wParam.ToInt64() == SignalW && lParam.ToInt64() == SignalL)
|
||||
{
|
||||
Signaled?.Invoke();
|
||||
Signaled?.Invoke(null);
|
||||
}
|
||||
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ using Avalonia.Win32.Input;
|
|||
using Avalonia.Win32.Interop;
|
||||
using static Avalonia.Win32.Interop.UnmanagedMethods;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Threading;
|
||||
#if NETSTANDARD
|
||||
using Win32Exception = Avalonia.Win32.NetStandard.AvaloniaWin32Exception;
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,7 @@ using CoreAnimation;
|
|||
using Foundation;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Shared.PlatformSupport;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace Avalonia.iOS
|
||||
{
|
||||
|
@ -18,7 +19,7 @@ namespace Avalonia.iOS
|
|||
public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
|
||||
public bool CurrentThreadIsLoopThread => NSThread.Current.IsMainThread;
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
public void RunLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
//Mobile platforms are using external main loop
|
||||
|
@ -53,7 +54,7 @@ namespace Avalonia.iOS
|
|||
public IDisposable StartTimer(TimeSpan interval, Action tick)
|
||||
=> NSTimer.CreateRepeatingScheduledTimer(interval, _ => tick());
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
|
@ -65,7 +66,7 @@ namespace Avalonia.iOS
|
|||
{
|
||||
lock (this)
|
||||
_signaled = false;
|
||||
Signaled?.Invoke();
|
||||
Signaled?.Invoke(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Reactive.Subjects;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.UnitTests;
|
||||
using Xunit;
|
||||
|
||||
|
@ -147,14 +148,14 @@ namespace Avalonia.Base.UnitTests
|
|||
|
||||
public bool CurrentThreadIsLoopThread { get; set; }
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
|
||||
public void RunLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ using Avalonia.Platform;
|
|||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
using Avalonia.Threading;
|
||||
#if AVALONIA_CAIRO
|
||||
using Avalonia.Cairo;
|
||||
#elif AVALONIA_SKIA
|
||||
|
@ -155,14 +155,14 @@ namespace Avalonia.Direct2D1.RenderTests
|
|||
|
||||
public Thread MainThread { get; set; }
|
||||
|
||||
public event Action Signaled;
|
||||
public event Action<DispatcherPriority?> Signaled;
|
||||
|
||||
public void RunLoop(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
public void Signal(DispatcherPriority prio)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче