From 9c42b33d082c758d9606b64db2f5eec862fb82c7 Mon Sep 17 00:00:00 2001 From: Tom Butterworth Date: Sat, 4 Apr 2020 14:50:26 +0100 Subject: [PATCH] Use a dispatch queue instead of the main CFRunLoop - permits use of Syphon in processes without a main CFRunLoop (such as XPC services) - receipt of messages is no longer interrupted by eg UI activity --- SyphonCFMessageReceiver.m | 44 ++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/SyphonCFMessageReceiver.m b/SyphonCFMessageReceiver.m index 6b3e6cf..725e1ef 100644 --- a/SyphonCFMessageReceiver.m +++ b/SyphonCFMessageReceiver.m @@ -31,6 +31,9 @@ #import "SyphonMessaging.h" #import +static dispatch_queue_t theQueue = NULL; +static int theCount = 0; + static CFDataRef MessageReturnCallback ( CFMessagePortRef local, SInt32 msgid, @@ -53,7 +56,31 @@ @implementation SyphonCFMessageReceiver { @private CFMessagePortRef _port; - CFRunLoopSourceRef _runLoopSource; +} + ++ (dispatch_queue_t)addUser +{ + @synchronized(self) { + theCount++; + if (!theQueue) + { + dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, -1); + theQueue = dispatch_queue_create("info.v002.syphon.messaging", attributes); + } + } + return theQueue; +} + ++ (void)endUser +{ + @synchronized(self) { + theCount--; + if (theCount == 0) + { + dispatch_release(theQueue); + theQueue = NULL; + } + } } - (id)initForName:(NSString *)name protocol:(NSString *)protocolName handler:(void (^)(id data, uint32_t type))handler @@ -71,24 +98,25 @@ - (id)initForName:(NSString *)name protocol:(NSString *)protocolName handler:(vo [self release]; return nil; } - _runLoopSource = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, _port, 0); - // TODO: Think about which run loop we want to be in (current thread, our own private, main, or what?) - CFRunLoopAddSource(CFRunLoopGetMain(), _runLoopSource, kCFRunLoopCommonModes); + CFMessagePortSetDispatchQueue(_port, [[self class] addUser]); } return self; } - (void)dealloc { - if (_runLoopSource) CFRelease(_runLoopSource); if (_port) CFRelease(_port); [super dealloc]; } - (void)invalidate { - if (_port) CFMessagePortInvalidate(_port); - if (_runLoopSource) CFRunLoopSourceInvalidate(_runLoopSource); - [super invalidate]; + if (_port) + { + CFMessagePortInvalidate(_port); + // we only called addUser if _port was created + [[self class] endUser]; + } + [super invalidate]; } @end