Skip to content

Commit

Permalink
Initial refactor to permit user subclasses
Browse files Browse the repository at this point in the history
- Existing public API is unchanged
- New SyphonServerBase, SyphonClientBase allow any IOSurface-based subclass to be added outside the framework
- SyphonImage likewise refactored
- Additions to the framework can be contained in new files without touching existing code
- More work to follow
  • Loading branch information
bangnoise committed Sep 28, 2019
1 parent c404f3c commit e02d781
Show file tree
Hide file tree
Showing 18 changed files with 805 additions and 471 deletions.
2 changes: 2 additions & 0 deletions Exported_Symbols.exp
Expand Up @@ -31,7 +31,9 @@


SYPHON_UNIQUE_CLASS_SYMBOL(SyphonClient)
SYPHON_UNIQUE_CLASS_SYMBOL(SyphonClientBase)
SYPHON_UNIQUE_CLASS_SYMBOL(SyphonServer)
SYPHON_UNIQUE_CLASS_SYMBOL(SyphonServerBase)
SYPHON_UNIQUE_CLASS_SYMBOL(SyphonServerDirectory)
SYPHON_UNIQUE_CLASS_SYMBOL(SyphonImage)

Expand Down
22 changes: 21 additions & 1 deletion Syphon.xcodeproj/project.pbxproj
Expand Up @@ -61,6 +61,8 @@
E218B67718436D3B004FD9E3 /* SyphonClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B0906C411CBB1C100BCBE41 /* SyphonClient.h */; };
E218B67818436D3F004FD9E3 /* SyphonImage.h in Headers */ = {isa = PBXBuildFile; fileRef = BD038870122EA9FF007725FF /* SyphonImage.h */; };
E218B67918436D41004FD9E3 /* SyphonServerDirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = BD606D6611D2842D00E02702 /* SyphonServerDirectory.h */; };
E219FB59233CDC3B00FB7F63 /* SyphonClientBase.h in Headers */ = {isa = PBXBuildFile; fileRef = E219FB57233CDC3B00FB7F63 /* SyphonClientBase.h */; };
E219FB5A233CDC3B00FB7F63 /* SyphonClientBase.m in Sources */ = {isa = PBXBuildFile; fileRef = E219FB58233CDC3B00FB7F63 /* SyphonClientBase.m */; };
E28D0C9A1D8F43380036DF26 /* SyphonServerRendererCore.h in Headers */ = {isa = PBXBuildFile; fileRef = E28D0C981D8F43380036DF26 /* SyphonServerRendererCore.h */; };
E28D0C9B1D8F43380036DF26 /* SyphonServerRendererCore.m in Sources */ = {isa = PBXBuildFile; fileRef = E28D0C991D8F43380036DF26 /* SyphonServerRendererCore.m */; };
E28D0CA81D9296520036DF26 /* SyphonShader.h in Headers */ = {isa = PBXBuildFile; fileRef = E28D0CA61D9296520036DF26 /* SyphonShader.h */; };
Expand All @@ -71,6 +73,8 @@
E28D0CB11D9542B30036DF26 /* SyphonVertices.m in Sources */ = {isa = PBXBuildFile; fileRef = E28D0CAF1D9542B30036DF26 /* SyphonVertices.m */; };
E28D0CB41D95770C0036DF26 /* SyphonServerVertices.h in Headers */ = {isa = PBXBuildFile; fileRef = E28D0CB21D95770C0036DF26 /* SyphonServerVertices.h */; };
E28D0CB51D95770C0036DF26 /* SyphonServerVertices.m in Sources */ = {isa = PBXBuildFile; fileRef = E28D0CB31D95770C0036DF26 /* SyphonServerVertices.m */; };
E2CF04FE227398E600B8CD19 /* SyphonServerBase.h in Headers */ = {isa = PBXBuildFile; fileRef = E2CF04FC227398E600B8CD19 /* SyphonServerBase.h */; };
E2CF04FF227398E600B8CD19 /* SyphonServerBase.m in Sources */ = {isa = PBXBuildFile; fileRef = E2CF04FD227398E600B8CD19 /* SyphonServerBase.m */; };
E2D6C8881D8B470E00108260 /* SyphonCGL.c in Sources */ = {isa = PBXBuildFile; fileRef = E2D6C8861D8B470E00108260 /* SyphonCGL.c */; };
E2D6C8891D8B470E00108260 /* SyphonCGL.h in Headers */ = {isa = PBXBuildFile; fileRef = E2D6C8871D8B470E00108260 /* SyphonCGL.h */; };
E2D6C88C1D8B4A6D00108260 /* SyphonServerRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = E2D6C88A1D8B4A6D00108260 /* SyphonServerRenderer.h */; };
Expand Down Expand Up @@ -146,6 +150,8 @@
E21003C51D85F9320066E934 /* SyphonIOSurfaceImageLegacy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SyphonIOSurfaceImageLegacy.m; sourceTree = "<group>"; };
E21003C81D85FAD00066E934 /* SyphonIOSurfaceImageCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyphonIOSurfaceImageCore.h; sourceTree = "<group>"; };
E21003C91D85FAD00066E934 /* SyphonIOSurfaceImageCore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SyphonIOSurfaceImageCore.m; sourceTree = "<group>"; };
E219FB57233CDC3B00FB7F63 /* SyphonClientBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SyphonClientBase.h; sourceTree = "<group>"; };
E219FB58233CDC3B00FB7F63 /* SyphonClientBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SyphonClientBase.m; sourceTree = "<group>"; };
E234B23F2257668400FBDC0C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
E26877562199C4E600B8E495 /* Building Syphon.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Building Syphon.md"; sourceTree = "<group>"; };
E28D0C981D8F43380036DF26 /* SyphonServerRendererCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyphonServerRendererCore.h; sourceTree = "<group>"; };
Expand All @@ -158,6 +164,8 @@
E28D0CAF1D9542B30036DF26 /* SyphonVertices.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SyphonVertices.m; sourceTree = "<group>"; };
E28D0CB21D95770C0036DF26 /* SyphonServerVertices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyphonServerVertices.h; sourceTree = "<group>"; };
E28D0CB31D95770C0036DF26 /* SyphonServerVertices.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SyphonServerVertices.m; sourceTree = "<group>"; };
E2CF04FC227398E600B8CD19 /* SyphonServerBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SyphonServerBase.h; sourceTree = "<group>"; };
E2CF04FD227398E600B8CD19 /* SyphonServerBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SyphonServerBase.m; sourceTree = "<group>"; };
E2D6C8861D8B470E00108260 /* SyphonCGL.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SyphonCGL.c; sourceTree = "<group>"; };
E2D6C8871D8B470E00108260 /* SyphonCGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyphonCGL.h; sourceTree = "<group>"; };
E2D6C88A1D8B4A6D00108260 /* SyphonServerRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyphonServerRenderer.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -280,6 +288,7 @@
E28D0CAF1D9542B30036DF26 /* SyphonVertices.m */,
E28D0CB21D95770C0036DF26 /* SyphonServerVertices.h */,
E28D0CB31D95770C0036DF26 /* SyphonServerVertices.m */,
E2CF04FD227398E600B8CD19 /* SyphonServerBase.m */,
);
name = Server;
sourceTree = "<group>";
Expand All @@ -288,6 +297,7 @@
isa = PBXGroup;
children = (
1B0906C511CBB1C100BCBE41 /* SyphonClient.m */,
E219FB58233CDC3B00FB7F63 /* SyphonClientBase.m */,
1B09098511CD9A1C00BCBE41 /* SyphonClientConnectionManager.h */,
1B09098611CD9A1C00BCBE41 /* SyphonClientConnectionManager.m */,
);
Expand Down Expand Up @@ -336,7 +346,9 @@
children = (
1B0906C811CBB1CE00BCBE41 /* Syphon.h */,
1B0906BE11CBB0F500BCBE41 /* SyphonServer.h */,
E2CF04FC227398E600B8CD19 /* SyphonServerBase.h */,
1B0906C411CBB1C100BCBE41 /* SyphonClient.h */,
E219FB57233CDC3B00FB7F63 /* SyphonClientBase.h */,
BD038870122EA9FF007725FF /* SyphonImage.h */,
BD606D6611D2842D00E02702 /* SyphonServerDirectory.h */,
);
Expand Down Expand Up @@ -422,6 +434,7 @@
E218B67618436D38004FD9E3 /* SyphonServer.h in Headers */,
E218B67718436D3B004FD9E3 /* SyphonClient.h in Headers */,
E28D0C9A1D8F43380036DF26 /* SyphonServerRendererCore.h in Headers */,
E219FB59233CDC3B00FB7F63 /* SyphonClientBase.h in Headers */,
E218B67818436D3F004FD9E3 /* SyphonImage.h in Headers */,
E218B67918436D41004FD9E3 /* SyphonServerDirectory.h in Headers */,
E28D0CB01D9542B30036DF26 /* SyphonVertices.h in Headers */,
Expand All @@ -434,6 +447,7 @@
E2D6C88C1D8B4A6D00108260 /* SyphonServerRenderer.h in Headers */,
E2D6C8901D8B4DED00108260 /* SyphonServerRendererLegacy.h in Headers */,
BDB8DA311211F59A0028D250 /* SyphonCFMessageReceiver.h in Headers */,
E2CF04FE227398E600B8CD19 /* SyphonServerBase.h in Headers */,
BDB8DA351211F59A0028D250 /* SyphonMessageSender.h in Headers */,
BDB8DA371211F59A0028D250 /* SyphonCFMessageSender.h in Headers */,
BDB8DAF51211FA7F0028D250 /* SyphonMessaging.h in Headers */,
Expand Down Expand Up @@ -547,17 +561,21 @@
"$(SRCROOT)/SyphonServerDirectory.h",
"$(SRCROOT)/SyphonBuildMacros.h",
"$(SRCROOT)/SyphonImage.h",
"$(SRCROOT)/SyphonServerBase.h",
"$(SRCROOT)/SyphonClientBase.h",
);
name = "Generate Public Headers";
outputPaths = (
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonClient.h,
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonServer.h,
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonServerDirectory.h,
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonImage.h,
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonServerBase.h,
$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/SyphonClientBase.h,
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "mkdir -p \"$DERIVED_FILE_DIR\"\ncombined=\"\"\nfor def in $GCC_PREPROCESSOR_DEFINITIONS\ndo\ncombined=\"${combined} -D${def}\"\ndone\nfor header in \"SyphonClient\" \"SyphonServer\" \"SyphonServerDirectory\" \"SyphonImage\"\ndo\nsed 's:#import://SYPHON_IMPORT_PLACEHOLDER:' \"$SRCROOT/${header}.h\" > \"$DERIVED_FILE_DIR/${header}_stage_1.h\"\nclang -E -C -P -nostdinc ${combined} -DSYPHON_HEADER_BUILD_PHASE -include \"$SRCROOT/SyphonBuildMacros.h\" \"$DERIVED_FILE_DIR/${header}_stage_1.h\" -o \"$DERIVED_FILE_DIR/${header}_stage_2.h\"\nsed 's://SYPHON_IMPORT_PLACEHOLDER:#import:' \"$DERIVED_FILE_DIR/${header}_stage_2.h\" > \"$DERIVED_FILE_DIR/${header}_stage_3.h\"\nsed '/./,$!d' \"$DERIVED_FILE_DIR/${header}_stage_3.h\" > \"$DERIVED_FILE_DIR/${header}_stage_4.h\"\ncat -s \"$DERIVED_FILE_DIR/${header}_stage_4.h\" > \"$DERIVED_FILE_DIR/${header}.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_1.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_2.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_3.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_4.h\"\ncp \"$DERIVED_FILE_DIR/${header}.h\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/${header}.h\"\ndone\n";
shellScript = "mkdir -p \"$DERIVED_FILE_DIR\"\ncombined=\"\"\nfor def in $GCC_PREPROCESSOR_DEFINITIONS\ndo\ncombined=\"${combined} -D${def}\"\ndone\nfor header in \"SyphonClient\" \"SyphonClientBase\" \"SyphonServer\" \"SyphonServerBase\" \"SyphonServerDirectory\" \"SyphonImage\"\ndo\nsed 's:#import://SYPHON_IMPORT_PLACEHOLDER:' \"$SRCROOT/${header}.h\" > \"$DERIVED_FILE_DIR/${header}_stage_1.h\"\nclang -E -C -P -nostdinc ${combined} -DSYPHON_HEADER_BUILD_PHASE -include \"$SRCROOT/SyphonBuildMacros.h\" \"$DERIVED_FILE_DIR/${header}_stage_1.h\" -o \"$DERIVED_FILE_DIR/${header}_stage_2.h\"\nsed 's://SYPHON_IMPORT_PLACEHOLDER:#import:' \"$DERIVED_FILE_DIR/${header}_stage_2.h\" > \"$DERIVED_FILE_DIR/${header}_stage_3.h\"\nsed '/./,$!d' \"$DERIVED_FILE_DIR/${header}_stage_3.h\" > \"$DERIVED_FILE_DIR/${header}_stage_4.h\"\ncat -s \"$DERIVED_FILE_DIR/${header}_stage_4.h\" > \"$DERIVED_FILE_DIR/${header}.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_1.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_2.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_3.h\"\nrm \"$DERIVED_FILE_DIR/${header}_stage_4.h\"\ncp \"$DERIVED_FILE_DIR/${header}.h\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Headers/${header}.h\"\ndone\n";
};
BDFE6806122866C7009C2E21 /* Generate Exported Symbols File */ = {
isa = PBXShellScriptBuildPhase;
Expand Down Expand Up @@ -598,6 +616,7 @@
BDB8DA321211F59A0028D250 /* SyphonCFMessageReceiver.m in Sources */,
BDB8DA361211F59A0028D250 /* SyphonMessageSender.m in Sources */,
BDB8DA381211F59A0028D250 /* SyphonCFMessageSender.m in Sources */,
E219FB5A233CDC3B00FB7F63 /* SyphonClientBase.m in Sources */,
E28D0CAD1D930B9F0036DF26 /* SyphonServerShader.m in Sources */,
BDB8DAF61211FA7F0028D250 /* SyphonMessaging.m in Sources */,
E21003C71D85F9320066E934 /* SyphonIOSurfaceImageLegacy.m in Sources */,
Expand All @@ -606,6 +625,7 @@
E28D0CB11D9542B30036DF26 /* SyphonVertices.m in Sources */,
E2DE7FD412495BF50081453B /* SyphonMessageQueue.m in Sources */,
E2D6C88D1D8B4A6D00108260 /* SyphonServerRenderer.m in Sources */,
E2CF04FF227398E600B8CD19 /* SyphonServerBase.m in Sources */,
BDFBD77E126F4D8800075A23 /* SyphonDispatch.c in Sources */,
BDFAE527148CDA84008C9E6F /* SyphonOpenGLFunctions.c in Sources */,
E21003CB1D85FAD00066E934 /* SyphonIOSurfaceImageCore.m in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion SyphonClient.h
Expand Up @@ -29,6 +29,7 @@

#import <Foundation/Foundation.h>
#import <OpenGL/OpenGL.h>
#import <Syphon/SyphonClientBase.h>

#define SYPHON_CLIENT_UNIQUE_CLASS_NAME SYPHON_UNIQUE_CLASS_NAME(SyphonClient)
#define SYPHON_IMAGE_UNIQUE_CLASS_NAME SYPHON_UNIQUE_CLASS_NAME(SyphonImage)
Expand All @@ -45,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
It is safe to access instances of this class across threads, with the usual limitatiions related to OpenGL. The calls to SyphonClient which may cause work to be done in a GL context are: -newFrameImage, -stop and -release.
*/

@interface SYPHON_CLIENT_UNIQUE_CLASS_NAME : NSObject
@interface SYPHON_CLIENT_UNIQUE_CLASS_NAME : SyphonClientBase

/*!
Returns a new client instance for the described server. You should check the isValid property after initialization to ensure a connection was made to the server.
Expand Down
161 changes: 31 additions & 130 deletions SyphonClient.m
Expand Up @@ -29,41 +29,27 @@


#import "SyphonClient.h"
#import "SyphonServerDirectory.h"
#import "SyphonPrivate.h"
#import "SyphonClientConnectionManager.h"
#import "SyphonPrivate.h" // TODO: using it?
#import "SyphonClientConnectionManager.h" // TODO: using it?
#import "SyphonCGL.h"
#import "SyphonIOSurfaceImageCore.h"
#import "SyphonIOSurfaceImageLegacy.h"

#import "SyphonCGL.h"

#import <libkern/OSAtomic.h>

@implementation SyphonClient
{
@private
id _connectionManager;
NSUInteger _lastFrameID;
void (^_handler)(id);
int32_t _status;
int32_t _lock;
CGLContextObj _context;
int32_t _lock;
CGLContextObj _shareContext;
SYPHON_IMAGE_UNIQUE_CLASS_NAME *_frame;
SyphonImage *_frame;
int32_t _frameValid;
NSDictionary *_serverDescription;
}

static void *SyphonClientServersContext = &SyphonClientServersContext;

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey
{
if ([theKey isEqualToString:@"serverDescription"])
{
return NO;
}
else
{
return [super automaticallyNotifiesObserversForKey:theKey];
}
}
@dynamic isValid, serverDescription, hasNewFrame;

#if SYPHON_DEBUG_NO_DRAWING
+ (void)load
Expand All @@ -73,21 +59,11 @@ + (void)load
}
#endif

- (id)init
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}

- (id)initWithServerDescription:(NSDictionary *)description context:(CGLContextObj)context options:(NSDictionary *)options newFrameHandler:(void (^)(SyphonClient *client))handler
{
self = [super init];
self = [super initWithServerDescription:description options:options newFrameHandler:handler];
if (self)
{
_status = 1;

_connectionManager = [[SyphonClientConnectionManager alloc] initWithServerDescription:description];
_handler = [handler copy]; // copy don't retain
_lock = OS_SPINLOCK_INIT;
#ifdef SYPHON_CORE_SHARE
_shareContext = CGLRetainContext(context);
Expand All @@ -102,48 +78,20 @@ - (id)initWithServerDescription:(NSDictionary *)description context:(CGLContextO
#else
_context = CGLRetainContext(context);
#endif
_serverDescription = [description retain];

[[SyphonServerDirectory sharedDirectory] addObserver:self
forKeyPath:@"servers"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:SyphonClientServersContext];

NSNumber *dictionaryVersion = [description objectForKey:SyphonServerDescriptionDictionaryVersionKey];
if (dictionaryVersion == nil
|| [dictionaryVersion unsignedIntValue] > kSyphonDictionaryVersion
|| _connectionManager == nil)
{
[self release];
return nil;
}

[(SyphonClientConnectionManager *)_connectionManager addInfoClient:(id <SyphonInfoReceiving>)self
isFrameClient:handler != nil ? YES : NO];
}
return self;
}

- (void) dealloc
{
[[SyphonServerDirectory sharedDirectory] removeObserver:self forKeyPath:@"servers"];
[self stop];
[_handler release];
[_serverDescription release];
[super dealloc];
}

- (void)stop
{
OSSpinLockLock(&_lock);
if (_status == 1)
{
[(SyphonClientConnectionManager *)_connectionManager removeInfoClient:(id <SyphonInfoReceiving>)self
isFrameClient:_handler != nil ? YES : NO];
[(SyphonClientConnectionManager *)_connectionManager release];
_connectionManager = nil;
_status = 0;
}
[super stop];
OSSpinLockLock(&_lock);
[_frame release];
_frame = nil;
_frameValid = NO;
Expand All @@ -169,22 +117,6 @@ - (CGLContextObj)context
#endif
}

- (BOOL)isValid
{
OSSpinLockLock(&_lock);
BOOL result = ((SyphonClientConnectionManager *)_connectionManager).isValid;
OSSpinLockUnlock(&_lock);
return result;
}

- (void)receiveNewFrame
{
if (_handler)
{
_handler(self);
}
}

- (void)invalidateFrame
{
/*
Expand All @@ -194,66 +126,35 @@ - (void)invalidateFrame
OSAtomicTestAndClearBarrier(0, &_frameValid);
}

#pragma mark Rendering frames
- (BOOL)hasNewFrame
{
BOOL result;
OSSpinLockLock(&_lock);
result = _lastFrameID != ((SyphonClientConnectionManager *)_connectionManager).frameID;
OSSpinLockUnlock(&_lock);
return result;
}
#pragma mark Vending frames

- (SyphonImage *)newFrameImage
{
OSSpinLockLock(&_lock);
_lastFrameID = [(SyphonClientConnectionManager *)_connectionManager frameID];
if (_frameValid == 0)
if (_frameValid == 0)
{
[_frame release];
_frame = [(SyphonClientConnectionManager *)_connectionManager newFrameForContext:_context];
IOSurfaceRef surface = [self newSurface];
if (surface)
{
if (SyphonOpenGLContextIsLegacy(_context))
{
_frame = [[SyphonIOSurfaceImageLegacy alloc] initWithSurface:surface forContext:_context];
}
else
{
_frame = [[SyphonIOSurfaceImageCore alloc] initWithSurface:surface forContext:_context];
}
CFRelease(surface);
}
else
{
_frame = nil;
}
OSAtomicTestAndSetBarrier(0, &_frameValid);
}
OSSpinLockUnlock(&_lock);
return [_frame retain];
}

- (NSDictionary *)serverDescription
{
OSSpinLockLock(&_lock);
NSDictionary *description = _serverDescription;
OSSpinLockUnlock(&_lock);
return description;
}

#pragma mark Changes
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if (context == SyphonClientServersContext)
{
NSUInteger kind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
if (kind == NSKeyValueChangeSetting || kind == NSKeyValueChangeReplacement)
{
NSArray *servers = change[NSKeyValueChangeNewKey];
NSString *uuid = _serverDescription[SyphonServerDescriptionUUIDKey];
for (NSDictionary *description in servers) {
if ([description[SyphonServerDescriptionUUIDKey] isEqualToString:uuid] &&
![_serverDescription isEqualToDictionary:description])
{
[self willChangeValueForKey:@"serverDescription"];
description = [description copy];
OSSpinLockLock(&_lock);
[_serverDescription release];
_serverDescription = description;
OSSpinLockUnlock(&_lock);
[self didChangeValueForKey:@"serverDescription"];
}
}
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end

0 comments on commit e02d781

Please sign in to comment.