using CPF.Mac.Foundation; using CPF.Mac.ObjCRuntime; using System; using System.Runtime.InteropServices; namespace CPF.Mac.CoreFoundation { public class CFRunLoop : INativeObject, IDisposable { private static IntPtr CoreFoundationLibraryHandle = Dlfcn.dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", 0); internal IntPtr handle; private static NSString _CFDefaultRunLoopMode; private static NSString _CFRunLoopCommonModes; public const string ModeDefault = "kCFRunLoopDefaultMode"; public const string ModeCommon = "kCFRunLoopCommonModes"; public static NSString CFDefaultRunLoopMode { get { if (_CFDefaultRunLoopMode == null) { _CFDefaultRunLoopMode = Dlfcn.GetStringConstant(CoreFoundationLibraryHandle, "kCFRunLoopDefaultMode"); } return _CFDefaultRunLoopMode; } } public static NSString CFRunLoopCommonModes { get { if (_CFRunLoopCommonModes == null) { _CFRunLoopCommonModes = Dlfcn.GetStringConstant(CoreFoundationLibraryHandle, "kCFRunLoopCommonModes"); } return _CFRunLoopCommonModes; } } public static CFRunLoop Current => new CFRunLoop(CFRunLoopGetCurrent()); public static CFRunLoop Main => new CFRunLoop(CFRunLoopGetMain()); public bool IsWaiting => CFRunLoopIsWaiting(handle) != 0; public IntPtr Handle => handle; [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern IntPtr CFRunLoopGetCurrent(); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern IntPtr CFRunLoopGetMain(); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern void CFRunLoopRun(); public void Run() { CFRunLoopRun(); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern void CFRunLoopStop(IntPtr loop); public void Stop() { CFRunLoopStop(handle); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern void CFRunLoopWakeUp(IntPtr loop); public void WakeUp() { CFRunLoopWakeUp(handle); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern int CFRunLoopIsWaiting(IntPtr loop); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern int CFRunLoopRunInMode(IntPtr mode, double seconds, int returnAfterSourceHandled); public CFRunLoopExitReason RunInMode(NSString mode, double seconds, bool returnAfterSourceHandled) { if (mode == null) { throw new ArgumentNullException("mode"); } return (CFRunLoopExitReason)CFRunLoopRunInMode(mode.Handle, seconds, returnAfterSourceHandled ? 1 : 0); } [Obsolete("Use the NSString version of CFRunLoop.RunInMode() instead.")] public CFRunLoopExitReason RunInMode(string mode, double seconds, bool returnAfterSourceHandled) { if (mode == null) { throw new ArgumentNullException("mode"); } CFString cFString = new CFString(mode); int result = CFRunLoopRunInMode(cFString.Handle, seconds, returnAfterSourceHandled ? 1 : 0); cFString.Dispose(); return (CFRunLoopExitReason)result; } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern void CFRunLoopAddSource(IntPtr loop, IntPtr source, IntPtr mode); public void AddSource(CFRunLoopSource source, NSString mode) { if (mode == null) { throw new ArgumentNullException("mode"); } CFRunLoopAddSource(handle, source.Handle, mode.Handle); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern bool CFRunLoopContainsSource(IntPtr loop, IntPtr source, IntPtr mode); public bool ContainsSource(CFRunLoopSource source, NSString mode) { if (mode == null) { throw new ArgumentNullException("mode"); } return CFRunLoopContainsSource(handle, source.Handle, mode.Handle); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern bool CFRunLoopRemoveSource(IntPtr loop, IntPtr source, IntPtr mode); public bool RemoveSource(CFRunLoopSource source, NSString mode) { if (mode == null) { throw new ArgumentNullException("mode"); } return CFRunLoopRemoveSource(handle, source.Handle, mode.Handle); } internal CFRunLoop(IntPtr handle) : this(handle, owns: false) { } [Preserve(Conditional = true)] internal CFRunLoop(IntPtr handle, bool owns) { if (!owns) { CFObject.CFRetain(handle); } this.handle = handle; } ~CFRunLoop() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (handle != IntPtr.Zero) { CFObject.CFRelease(handle); handle = IntPtr.Zero; } } public static bool operator ==(CFRunLoop a, CFRunLoop b) { return object.Equals(a, b); } public static bool operator !=(CFRunLoop a, CFRunLoop b) { return !object.Equals(a, b); } public override int GetHashCode() { return handle.GetHashCode(); } public override bool Equals(object other) { CFRunLoop cFRunLoop = other as CFRunLoop; if (cFRunLoop == null) { return false; } return cFRunLoop.Handle == Handle; } } }