From c99f0659bb67b7329163df3f80599c5ac52c5cad Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 2 Nov 1998 17:01:52 +0000 Subject: [PATCH] Added NSDistributedNotificationCenter stuff git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3162 72102866-910b-0410-8b05-ffd578937521 --- .../base/NSDistributedNotificationCenter.h | 78 ++++ Source/GNUmakefile | 2 + Source/NSDistributedNotificationCenter.m | 366 ++++++++++++++++++ 3 files changed, 446 insertions(+) create mode 100644 Headers/gnustep/base/NSDistributedNotificationCenter.h create mode 100644 Source/NSDistributedNotificationCenter.m diff --git a/Headers/gnustep/base/NSDistributedNotificationCenter.h b/Headers/gnustep/base/NSDistributedNotificationCenter.h new file mode 100644 index 000000000..431bf8d3e --- /dev/null +++ b/Headers/gnustep/base/NSDistributedNotificationCenter.h @@ -0,0 +1,78 @@ +/* Interface of NSDistributedNotificationCenter class + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Created: October 1998 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __NSDistributedNotificationCenter_h_GNUSTEP_BASE_INCLUDE +#define __NSDistributedNotificationCenter_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@class NSString; + +typedef enum { + NSNotificationSuspensionBehaviorDrop, + NSNotificationSuspensionBehaviorCoalesce, + NSNotificationSuspensionBehaviorHold, + NSNotificationSuspensionBehaviorDeliverImmediately +} NSNotificationSuspensionBehavior; + +extern NSString *NSLocalNotificationCenterType; + +@interface NSDistributedNotificationCenter : NSObject +{ + NSRecursiveLock *centerLock; /* For thread safety. */ + id remote; /* Proxy for center. */ + BOOL suspended; /* Is delivery suspended? */ +} ++ (id) defaultCenter; ++ (id) notificationCenterForType: (NSString*)type; + +- (void) addObserver: (id)anObserver + selector: (SEL)aSelector + name: (NSString*)notificationName + object: (NSString*)anObject; +- (void) addObserver: (id)anObserver + selector: (SEL)aSelector + name: (NSString*)notificationName + object: (NSString*)anObject + suspensionBehavior: (NSNotificationSuspensionBehavior)suspensionBehavior; +- (void) postNotification: (NSNotification*)notification; +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject; +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject + userInfo: (NSDictionary*)userInfo; +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject + userInfo: (NSDictionary*)userInfo + deliverImmediately: (BOOL)deliverImmediately; +- (void) removeObserver: (id)anObserver + name: (NSString*)notificationName + object: (NSString*)anObject; +- (void) setSuspended: (BOOL)suspended; +- (BOOL) suspended; + +@end + +#endif + diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 031914452..31b570a05 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -308,6 +308,7 @@ NSDebug.m \ NSDictionary.m \ NSDistantObject.m \ NSDistributedLock.m \ +NSDistributedNotificationCenter.m \ NSEnumerator.m \ NSException.m \ NSFileHandle.m \ @@ -407,6 +408,7 @@ Foundation/NSDebug.h \ Foundation/NSDictionary.h \ Foundation/NSDistantObject.h \ Foundation/NSDistributedLock.h \ +Foundation/NSDistributedNotificationCenter.h \ Foundation/NSEnumerator.h \ Foundation/NSException.h \ Foundation/NSFileHandle.h \ diff --git a/Source/NSDistributedNotificationCenter.m b/Source/NSDistributedNotificationCenter.m new file mode 100644 index 000000000..0a8fcd3a0 --- /dev/null +++ b/Source/NSDistributedNotificationCenter.m @@ -0,0 +1,366 @@ +/* Implementation of NSDistributedNotificationCenter class + Copyright (C) 1998 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Created: October 1998 + + This file is part of the GNUstep Base Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../Tools/gdnc.h" + +/* + * Global variables for distributed notification center types. + */ +NSString *NSLocalNotificationCenterType = + @"NSLocalNotificationCenterType"; + + +@interface NSDistributedNotificationCenter (Private) +- (void) _connect; +- (id) _invalidated: (NSNotification*)notification; +- (void) postNotificationName: (NSString*)name + object: (NSString*)object + userInfo: (NSData*)info + selector: (SEL)aSelector + to: (unsigned long)observer; +@end + +@implementation NSDistributedNotificationCenter + +static NSDistributedNotificationCenter *defCenter = nil; + ++ (id) defaultCenter +{ + return [self notificationCenterForType: NSLocalNotificationCenterType]; +} + ++ (id) notificationCenterForType: (NSString*)type +{ + NSAssert([type isEqual: NSLocalNotificationCenterType], + NSInvalidArgumentException); + if (defCenter == nil) + { + [gnustep_global_lock lock]; + if (defCenter == nil) + { + NS_DURING + { + id tmp; + + tmp = NSAllocateObject(self, 0, NSDefaultMallocZone()); + defCenter = (NSDistributedNotificationCenter*)[tmp init]; + } + NS_HANDLER + { + [gnustep_global_lock unlock]; + [localException raise]; + } + NS_ENDHANDLER + } + [gnustep_global_lock unlock]; + } + return defCenter; +} + +- (void) dealloc +{ + if ([[remote connectionForProxy] isValid]) + { + [remote unregisterClient: (id)self]; + } + [remote release]; + [super dealloc]; +} + +- (id) init +{ + NSAssert(centerLock == nil, NSInternalInconsistencyException); + centerLock = [NSRecursiveLock new]; + return self; +} + +- (void) addObserver: (id)anObserver + selector: (SEL)aSelector + name: (NSString*)notificationName + object: (NSString*)anObject +{ + [self addObserver: anObserver + selector: aSelector + name: notificationName + object: anObject + suspensionBehavior: NSNotificationSuspensionBehaviorCoalesce]; +} + +- (void) addObserver: (id)anObserver + selector: (SEL)aSelector + name: (NSString*)notificationName + object: (NSString*)anObject + suspensionBehavior: (NSNotificationSuspensionBehavior)suspensionBehavior +{ + if (anObserver == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"nil observer"]; + } + if (aSelector == 0) + { + [NSException raise: NSInvalidArgumentException + format: @"nul selector"]; + } + if (notificationName != nil || + [notificationName isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification name"]; + } + if (anObject != nil && [anObject isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification object"]; + } + if (anObject == nil && notificationName == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"notification name and object both nil"]; + } + + [centerLock lock]; + NS_DURING + { + [self _connect]; + [(id)remote addObserver: (unsigned long)anObserver + selector: aSelector + name: notificationName + object: anObject + suspensionBehavior: suspensionBehavior + for: (id)self]; + } + NS_HANDLER + { + [centerLock unlock]; + [localException raise]; + } + NS_ENDHANDLER + [centerLock unlock]; +} + +- (void) postNotification: (NSNotification*)notification +{ + [self postNotificationName: [notification name] + object: [notification object] + userInfo: [notification userInfo] + deliverImmediately: NO]; +} + +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject +{ + [self postNotificationName: notificationName + object: anObject + userInfo: nil + deliverImmediately: NO]; +} + +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject + userInfo: (NSDictionary*)userInfo +{ + [self postNotificationName: notificationName + object: anObject + userInfo: userInfo + deliverImmediately: NO]; +} + +- (void) postNotificationName: (NSString*)notificationName + object: (NSString*)anObject + userInfo: (NSDictionary*)userInfo + deliverImmediately: (BOOL)deliverImmediately +{ + if (notificationName == nil || + [notificationName isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification name"]; + } + if (anObject != nil && [anObject isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification object"]; + } + + [centerLock lock]; + NS_DURING + { + NSData *d; + + [self _connect]; + d = [NSArchiver archivedDataWithRootObject: userInfo]; + [(id)remote postNotificationName: notificationName + object: anObject + userInfo: d + deliverImmediately: deliverImmediately + for: (id)self]; + } + NS_HANDLER + { + [centerLock unlock]; + [localException raise]; + } + NS_ENDHANDLER + [centerLock unlock]; +} + +- (void) removeObserver: (id)anObserver + name: (NSString*)notificationName + object: (NSString*)anObject +{ + if (notificationName != nil && + [notificationName isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification name"]; + } + if (anObject != nil && [anObject isKindOfClass: [NSString class]] == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"invalid notification object"]; + } + + [centerLock lock]; + NS_DURING + { + [self _connect]; + [(id)remote removeObserver: (unsigned long)anObserver + name: notificationName + object: anObject + for: (id)self]; + } + NS_HANDLER + { + [centerLock unlock]; + [localException raise]; + } + NS_ENDHANDLER + [centerLock unlock]; +} + +- (void) setSuspended: (BOOL)flag +{ + [centerLock lock]; + NS_DURING + { + [self _connect]; + suspended = flag; + [(id)remote setSuspended: flag for: (id)self]; + } + NS_HANDLER + { + [centerLock unlock]; + [localException raise]; + } + NS_ENDHANDLER + [centerLock unlock]; +} + +- (BOOL) suspended +{ + return suspended; +} + +@end + +@implementation NSDistributedNotificationCenter (Private) + +- (void) _connect +{ + if (remote == nil) + { + /* + * Connect to the NSDistributedNotificationCenter for this host. + */ + remote = [NSConnection rootProxyForConnectionWithRegisteredName: + GDNC_SERVICE host: @""]; + if ((remote = [remote retain]) != nil) + { + NSConnection *c = [remote connectionForProxy]; + Protocol *p = @protocol(GDNCProtocol); + + [remote setProtocolForProxy: p]; + + /* + * Ask to be told if the copnnection goes away. + */ + [NSNotificationCenter + addObserver: self + selector: @selector(_invalidated:) + name: NSConnectionDidDieNotification + object: c]; + [remote registerClient: (id)self]; + } + else + { + [NSException raise: NSInternalInconsistencyException + format: @"unable to contact GDNC server"]; + } + } +} + +- (id) _invalidated: (NSNotification*)notification +{ + id connection = [notification object]; + + /* + * Tidy up now that the connection has gone away. + */ + [NSNotificationCenter removeObserver: self + name: NSConnectionDidDieNotification + object: connection]; + NSAssert(connection == [remote connectionForProxy], + NSInternalInconsistencyException); + [remote release]; + remote = nil; +} + +- (void) postNotificationName: (NSString*)name + object: (NSString*)object + userInfo: (NSData*)info + selector: (SEL)aSelector + to: (unsigned long)observer +{ + id userInfo; + NSNotification *notification; + id recipient = (id)observer; + + userInfo = [NSUnarchiver unarchiveObjectWithData: info]; + notification = [NSNotification notificationWithName: name + object: object + userInfo: userInfo]; + [recipient performSelector: aSelector withObject: notification]; +} + +@end +