diff --git a/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj b/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
index 49a122b8e12..eb4938c13ff 100644
--- a/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
+++ b/src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
@@ -3,6 +3,7 @@
net7.0-ios16.0
13.0
true
+ true
diff --git a/src/iOS/Avalonia.iOS/DispatcherImpl.cs b/src/iOS/Avalonia.iOS/DispatcherImpl.cs
index 8b3c747b5a1..9933126133e 100644
--- a/src/iOS/Avalonia.iOS/DispatcherImpl.cs
+++ b/src/iOS/Avalonia.iOS/DispatcherImpl.cs
@@ -2,12 +2,11 @@
using System;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Threading;
using Avalonia.Threading;
using CoreFoundation;
using Foundation;
-using ObjCRuntime;
-using CFIndex = System.IntPtr;
namespace Avalonia.iOS;
@@ -20,30 +19,28 @@ internal class DispatcherImpl : IDispatcherImplWithExplicitBackgroundProcessing
internal static readonly DispatcherImpl Instance = new();
private readonly Stopwatch _clock = Stopwatch.StartNew();
- private readonly Action _checkSignaledAction;
- private readonly Action _wakeUpLoopAction;
+ private readonly object _sync = new();
private readonly IntPtr _timer;
+ private readonly IntPtr _mainLoop;
+ private readonly IntPtr _mainQueue;
private Thread? _loopThread;
private bool _backgroundProcessingRequested, _signaled;
- private DispatcherImpl()
+ private unsafe DispatcherImpl()
{
- _checkSignaledAction = CheckSignaled;
- _wakeUpLoopAction = () =>
- {
- // This is needed to wakeup the loop if we are called from inside of BeforeWait hook
- };
+ _mainLoop = Interop.CFRunLoopGetMain();
+ _mainQueue = DispatchQueue.MainQueue.Handle.Handle;
var observer = Interop.CFRunLoopObserverCreate(IntPtr.Zero,
Interop.CFOptionFlags.kCFRunLoopAfterWaiting | Interop.CFOptionFlags.kCFRunLoopBeforeSources |
Interop.CFOptionFlags.kCFRunLoopBeforeWaiting,
- true, 0, ObserverCallback, IntPtr.Zero);
- Interop.CFRunLoopAddObserver(Interop.CFRunLoopGetMain(), observer, Interop.kCFRunLoopCommonModes);
+ 1, 0, &ObserverCallback, IntPtr.Zero);
+ Interop.CFRunLoopAddObserver(_mainLoop, observer, Interop.kCFRunLoopDefaultMode);
_timer = Interop.CFRunLoopTimerCreate(IntPtr.Zero,
Interop.CFAbsoluteTimeGetCurrent() + DistantFutureInterval,
- DistantFutureInterval, 0, 0, TimerCallback, IntPtr.Zero);
- Interop.CFRunLoopAddTimer(Interop.CFRunLoopGetMain(), _timer, Interop.kCFRunLoopCommonModes);
+ DistantFutureInterval, 0, 0, &TimerCallback, IntPtr.Zero);
+ Interop.CFRunLoopAddTimer(_mainLoop, _timer, Interop.kCFRunLoopDefaultMode);
}
public event Action? Signaled;
@@ -63,16 +60,16 @@ public bool CurrentThreadIsLoopThread
}
}
- public void Signal()
+ public unsafe void Signal()
{
- lock (this)
+ lock (_sync)
{
if (_signaled)
return;
_signaled = true;
- DispatchQueue.MainQueue.DispatchAsync(_checkSignaledAction);
- CFRunLoop.Main.WakeUp();
+ Interop.dispatch_async_f(_mainQueue, IntPtr.Zero, &CheckSignaled);
+ Interop.CFRunLoopWakeUp(_mainLoop);
}
}
@@ -86,18 +83,18 @@ public void UpdateTimer(long? dueTimeInMs)
public long Now => _clock.ElapsedMilliseconds;
- public void RequestBackgroundProcessing()
+ public unsafe void RequestBackgroundProcessing()
{
if (_backgroundProcessingRequested)
return;
_backgroundProcessingRequested = true;
- DispatchQueue.MainQueue.DispatchAsync(_wakeUpLoopAction);
+ Interop.dispatch_async_f(_mainQueue, IntPtr.Zero, &WakeUpCallback);
}
private void CheckSignaled()
{
bool signaled;
- lock (this)
+ lock (_sync)
{
signaled = _signaled;
_signaled = false;
@@ -109,13 +106,25 @@ private void CheckSignaled()
}
}
- [MonoPInvokeCallback(typeof(Interop.CFRunLoopObserverCallback))]
+ [UnmanagedCallersOnly]
+ private static void CheckSignaled(IntPtr context)
+ {
+ Instance.CheckSignaled();
+ }
+
+ [UnmanagedCallersOnly]
+ private static void WakeUpCallback(IntPtr context)
+ {
+
+ }
+
+ [UnmanagedCallersOnly]
private static void ObserverCallback(IntPtr observer, Interop.CFOptionFlags activity, IntPtr info)
{
if (activity == Interop.CFOptionFlags.kCFRunLoopBeforeWaiting)
{
bool triggerProcessing;
- lock (Instance)
+ lock (Instance._sync)
{
triggerProcessing = Instance._backgroundProcessingRequested;
Instance._backgroundProcessingRequested = false;
@@ -127,7 +136,7 @@ private static void ObserverCallback(IntPtr observer, Interop.CFOptionFlags acti
Instance.CheckSignaled();
}
- [MonoPInvokeCallback(typeof(Interop.CFRunLoopTimerCallback))]
+ [UnmanagedCallersOnly]
private static void TimerCallback(IntPtr timer, IntPtr info)
{
Instance.Timer?.Invoke();
diff --git a/src/iOS/Avalonia.iOS/Interop.cs b/src/iOS/Avalonia.iOS/Interop.cs
index c0b3506936f..b05ddafc9ad 100644
--- a/src/iOS/Avalonia.iOS/Interop.cs
+++ b/src/iOS/Avalonia.iOS/Interop.cs
@@ -7,11 +7,11 @@
namespace Avalonia.iOS;
-// TODO: use LibraryImport in NET7
-internal class Interop
+internal unsafe class Interop
{
internal const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
- internal static NativeHandle kCFRunLoopCommonModes = CFString.CreateNative("kCFRunLoopCommonModes");
+ internal const string libcLibrary = "/usr/lib/libc.dylib";
+ internal static NativeHandle kCFRunLoopDefaultMode = CFString.CreateNative("kCFRunLoopDefaultMode");
[Flags]
internal enum CFOptionFlags : ulong
@@ -20,26 +20,29 @@ internal enum CFOptionFlags : ulong
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopBeforeWaiting = (1UL << 5)
}
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- internal delegate void CFRunLoopObserverCallback(IntPtr observer, CFOptionFlags activity, IntPtr info);
-
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- internal delegate void CFRunLoopTimerCallback(IntPtr timer, IntPtr info);
+ [DllImport(libcLibrary)]
+ internal static extern void dispatch_async_f(IntPtr queue, IntPtr context, delegate* unmanaged dispatch);
+
[DllImport(CoreFoundationLibrary)]
internal static extern IntPtr CFRunLoopGetMain();
+
+ [DllImport(CoreFoundationLibrary)]
+ internal static extern IntPtr CFRunLoopGetCurrent();
+ [DllImport (CoreFoundationLibrary)]
+ internal static extern void CFRunLoopWakeUp(IntPtr rl);
+
[DllImport(CoreFoundationLibrary)]
internal static extern IntPtr CFRunLoopObserverCreate(IntPtr allocator, CFOptionFlags activities,
- bool repeats, int index, CFRunLoopObserverCallback callout, IntPtr context);
+ int repeats, int index, delegate* unmanaged callout, IntPtr context);
[DllImport(CoreFoundationLibrary)]
internal static extern IntPtr CFRunLoopAddObserver(IntPtr loop, IntPtr observer, IntPtr mode);
[DllImport(CoreFoundationLibrary)]
internal static extern IntPtr CFRunLoopTimerCreate(IntPtr allocator, double firstDate, double interval,
- CFOptionFlags flags, int order, CFRunLoopTimerCallback callout, IntPtr context);
+ CFOptionFlags flags, int order, delegate* unmanaged callout, IntPtr context);
[DllImport(CoreFoundationLibrary)]
internal static extern void CFRunLoopTimerSetTolerance(IntPtr timer, double tolerance);