mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Added Distributed notification center server stuff.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3161 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
56b9470195
commit
778a1d5d97
3 changed files with 821 additions and 3 deletions
|
@ -28,19 +28,20 @@ GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles
|
|||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
# The application to be compiled
|
||||
TOOL_NAME = defaults dread dwrite dremove
|
||||
TOOL_NAME = gdnc defaults dread dwrite dremove
|
||||
OBJC_PROGRAM_NAME = gdomap
|
||||
|
||||
# The source files to be compiled
|
||||
gdomap_C_FILES = gdomap.c
|
||||
gdnc_OBJC_FILES = gdnc.m
|
||||
defaults_OBJC_FILES = defaults.m
|
||||
dread_OBJC_FILES = dread.m
|
||||
dremove_OBJC_FILES = dremove.m
|
||||
dwrite_OBJC_FILES = dwrite.m
|
||||
|
||||
SOURCES = gdomap.c defaults.m dread.m dremove.m dwrite.m
|
||||
SOURCES = gdomap.c gdnc.m defaults.m dread.m dremove.m dwrite.m
|
||||
|
||||
HEADERS = gdomap.h
|
||||
HEADERS = gdomap.h gdnc.h
|
||||
|
||||
DIST_FILES = GNUmakefile Makefile.preamble Makefile.postamble \
|
||||
$(SOURCES) $(HEADERS)
|
||||
|
|
61
Tools/gdnc.h
Normal file
61
Tools/gdnc.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* Include for GNUstep Distributed NotificationCenter
|
||||
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
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.
|
||||
*/
|
||||
|
||||
#define GDNC_SERVICE @"GDNCServer"
|
||||
|
||||
@protocol GDNCClient
|
||||
- (void) postNotificationName: (NSString*)name
|
||||
object: (NSString*)object
|
||||
userInfo: (NSData*)info
|
||||
selector: (SEL)aSelector
|
||||
to: (unsigned long)observer;
|
||||
@end
|
||||
|
||||
@protocol GDNCProtocol
|
||||
- (void) addObserver: (unsigned long)anObserver
|
||||
selector: (SEL)aSelector
|
||||
name: (NSString*)notificationname
|
||||
object: (NSString*)anObject
|
||||
suspensionBehavior: (NSNotificationSuspensionBehavior)suspensionBehavior
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) postNotificationName: (NSString*)notificationName
|
||||
object: (NSString*)anObject
|
||||
userInfo: (NSData*)d
|
||||
deliverImmediately: (BOOL)deliverImmediately
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) registerClient: (id<GDNCClient>)client;
|
||||
|
||||
- (void) removeObserver: (unsigned long)anObserver
|
||||
name: (NSString*)notificationname
|
||||
object: (NSString*)anObject
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) setSuspended: (BOOL)flag
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) unregisterClient: (id<GDNCClient>)client;
|
||||
|
||||
@end
|
||||
|
756
Tools/gdnc.m
Normal file
756
Tools/gdnc.m
Normal file
|
@ -0,0 +1,756 @@
|
|||
/* Implementation of GNUstep Distributed Notification Center
|
||||
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
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 <Foundation/NSObject.h>
|
||||
#include <Foundation/NSConnection.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDistantObject.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSNotification.h>
|
||||
#include <Foundation/NSHashTable.h>
|
||||
#include <Foundation/NSMapTable.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#include <Foundation/NSDistributedNotificationCenter.h>
|
||||
|
||||
#include "gdnc.h"
|
||||
|
||||
@interface GDNCNotification : NSObject
|
||||
{
|
||||
@public
|
||||
NSString *name;
|
||||
NSString *object;
|
||||
NSData *info;
|
||||
}
|
||||
+ (GDNCNotification*) notificationWithName: (NSString*)notificationName
|
||||
object: (NSString*)notificationObject
|
||||
data: (NSData*)notificationData;
|
||||
@end
|
||||
|
||||
@implementation GDNCNotification
|
||||
- (void) dealloc
|
||||
{
|
||||
[name release];
|
||||
[object release];
|
||||
[info release];
|
||||
[super dealloc];
|
||||
}
|
||||
+ (GDNCNotification*) notificationWithName: (NSString*)notificationName
|
||||
object: (NSString*)notificationObject
|
||||
data: (NSData*)notificationData
|
||||
{
|
||||
GDNCNotification *tmp = [GDNCNotification alloc];
|
||||
|
||||
tmp->name = [notificationName retain];
|
||||
tmp->object = [notificationObject retain];
|
||||
tmp->info = [notificationData retain];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
/*
|
||||
* Information about a notification observer.
|
||||
*/
|
||||
@interface GDNCClient : NSObject
|
||||
{
|
||||
@public
|
||||
BOOL suspended;
|
||||
id <GDNCClient> client;
|
||||
NSMutableArray *observers;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GDNCClient
|
||||
- (void) dealloc
|
||||
{
|
||||
[observers release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
observers = [NSMutableArray new];
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Information about a notification observer.
|
||||
*/
|
||||
@interface GDNCObserver : NSObject
|
||||
{
|
||||
@public
|
||||
unsigned observer;
|
||||
NSString *notificationName;
|
||||
NSString *notificationObject;
|
||||
SEL selector;
|
||||
GDNCClient *client;
|
||||
NSMutableArray *queue;
|
||||
NSNotificationSuspensionBehavior behavior;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GDNCObserver
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[queue release];
|
||||
[notificationName release];
|
||||
[notificationObject release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
queue = [[NSMutableArray alloc] initWithCapacity: 1];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface GDNCServer : NSObject <GDNCProtocol>
|
||||
{
|
||||
NSConnection *conn;
|
||||
NSMapTable *connections;
|
||||
NSHashTable *allObservers;
|
||||
NSMutableDictionary *observersForNames;
|
||||
NSMutableDictionary *observersForObjects;
|
||||
}
|
||||
|
||||
- (void) addObserver: (unsigned long)anObserver
|
||||
selector: (SEL)aSelector
|
||||
name: (NSString*)notificationname
|
||||
object: (NSString*)anObject
|
||||
suspensionBehavior: (NSNotificationSuspensionBehavior)suspensionBehavior
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (NSConnection*) connection: (NSConnection*)ancestor
|
||||
didConnect: (NSConnection*)newConn;
|
||||
|
||||
- (id) connectionBecameInvalid: (NSNotification*)notification;
|
||||
|
||||
- (void) postNotificationName: (NSString*)notificationName
|
||||
object: (NSString*)anObject
|
||||
userInfo: (NSData*)d
|
||||
deliverImmediately: (BOOL)deliverImmediately
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) removeObserver: (GDNCObserver*)observer;
|
||||
|
||||
- (void) removeObserversForClients: (NSMapTable*)clients;
|
||||
|
||||
- (void) removeObserver: (unsigned long)anObserver
|
||||
name: (NSString*)notificationname
|
||||
object: (NSString*)anObject
|
||||
for: (id<GDNCClient>)client;
|
||||
|
||||
- (void) setSuspended: (BOOL)flag
|
||||
for: (id<GDNCClient>)client;
|
||||
@end
|
||||
|
||||
@implementation GDNCServer
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
NSMapEnumerator enumerator;
|
||||
NSConnection *connection;
|
||||
NSMapTable *clients;
|
||||
|
||||
if (conn)
|
||||
{
|
||||
[NSNotificationCenter removeObserver: self
|
||||
name: NSConnectionDidDieNotification
|
||||
object: conn];
|
||||
[conn release];
|
||||
conn = nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all the client map tables in the connections map table and
|
||||
* ignore notifications from those connections.
|
||||
*/
|
||||
enumerator = NSEnumerateMapTable(connections);
|
||||
while (NSNextMapEnumeratorPair(&enumerator,
|
||||
(void**)&connection, (void**)&clients) == YES)
|
||||
{
|
||||
[NSNotificationCenter removeObserver: self
|
||||
name: NSConnectionDidDieNotification
|
||||
object: connection];
|
||||
[self removeObserversForClients: clients];
|
||||
NSFreeMapTable(clients);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now free the connections map itsself and the table of observers.
|
||||
*/
|
||||
NSFreeMapTable(connections);
|
||||
NSFreeHashTable(allObservers);
|
||||
|
||||
/*
|
||||
* And release the maps of notification names and objects.
|
||||
*/
|
||||
[observersForNames release];
|
||||
[observersForObjects release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
connections = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
||||
NSNonOwnedPointerMapValueCallBacks, 0);
|
||||
allObservers = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 0);
|
||||
observersForNames = [NSMutableDictionary new];
|
||||
observersForObjects = [NSMutableDictionary new];
|
||||
conn = [NSConnection newRegisteringAtName: GDNC_SERVICE
|
||||
withRootObject: self];
|
||||
if (conn == nil)
|
||||
{
|
||||
NSLog(@"gdnc - unable to register with name server - quiting.\n");
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get notifications for new connections and connection losses.
|
||||
*/
|
||||
[conn setDelegate: self];
|
||||
[NSNotificationCenter addObserver: self
|
||||
selector: @selector(connectionBecameInvalid:)
|
||||
name: NSConnectionDidDieNotification
|
||||
object: conn];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) addObserver: (unsigned long)anObserver
|
||||
selector: (SEL)aSelector
|
||||
name: (NSString*)notificationName
|
||||
object: (NSString*)anObject
|
||||
suspensionBehavior: (NSNotificationSuspensionBehavior)suspensionBehavior
|
||||
for: (id<GDNCClient>)client
|
||||
{
|
||||
GDNCClient *info;
|
||||
NSMapTable *clients;
|
||||
GDNCObserver *obs;
|
||||
NSConnection *connection;
|
||||
|
||||
connection = [(NSDistantObject*)client connectionForProxy];
|
||||
clients = (NSMapTable*)NSMapGet(connections, connection);
|
||||
if (clients == 0)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Unknown connection for new observer"];
|
||||
}
|
||||
info = (GDNCClient*)NSMapGet(clients, client);
|
||||
if (info == nil)
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Unknown client for new observer"];
|
||||
}
|
||||
|
||||
/*
|
||||
* Create new observer info and add to array of observers for this
|
||||
* client and the table of all observers.
|
||||
*/
|
||||
obs = [GDNCObserver new];
|
||||
obs->observer = anObserver;
|
||||
obs->client = info;
|
||||
obs->behavior = suspensionBehavior;
|
||||
obs->selector = aSelector;
|
||||
[info->observers addObject: obs];
|
||||
[obs release];
|
||||
NSHashInsert(allObservers, obs);
|
||||
|
||||
/*
|
||||
* Now add the observer to the lists of observers interested in it's
|
||||
* particular notification names and objects.
|
||||
*/
|
||||
if (anObject)
|
||||
{
|
||||
NSMutableArray *objList;
|
||||
|
||||
objList = [observersForObjects objectForKey: anObject];
|
||||
if (objList == nil)
|
||||
{
|
||||
objList = [NSMutableArray new];
|
||||
[observersForObjects setObject: objList forKey: anObject];
|
||||
[objList release];
|
||||
}
|
||||
/*
|
||||
* If possible use an existing string as the key.
|
||||
*/
|
||||
if ([objList count] > 0)
|
||||
{
|
||||
GDNCObserver *tmp = [objList objectAtIndex: 0];
|
||||
|
||||
anObject = tmp->notificationObject;
|
||||
}
|
||||
obs->notificationName = [anObject retain];
|
||||
[objList addObject: obs];
|
||||
}
|
||||
|
||||
if (notificationName)
|
||||
{
|
||||
NSMutableArray *namList;
|
||||
|
||||
namList = [observersForNames objectForKey: notificationName];
|
||||
if (namList == nil)
|
||||
{
|
||||
namList = [NSMutableArray new];
|
||||
[observersForNames setObject: namList forKey: notificationName];
|
||||
[namList release];
|
||||
}
|
||||
/*
|
||||
* If possible use an existing string as the key.
|
||||
*/
|
||||
if ([namList count] > 0)
|
||||
{
|
||||
GDNCObserver *tmp = [namList objectAtIndex: 0];
|
||||
|
||||
notificationName = tmp->notificationObject;
|
||||
}
|
||||
obs->notificationName = [notificationName retain];
|
||||
[namList addObject: obs];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (NSConnection*) connection: (NSConnection*)ancestor
|
||||
didConnect: (NSConnection*)newConn
|
||||
{
|
||||
NSMapTable *table;
|
||||
|
||||
[NSNotificationCenter addObserver: self
|
||||
selector: @selector(connectionBecameInvalid:)
|
||||
name: NSConnectionDidDieNotification
|
||||
object: newConn];
|
||||
[newConn setDelegate: self];
|
||||
/*
|
||||
* Create a new map table entry for this connection with a value that
|
||||
* is a table (normally with a single entry) containing registered
|
||||
* clients (proxies for NSDistributedNotificationCenter objects).
|
||||
*/
|
||||
table = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
NSMapInsert(connections, newConn, table);
|
||||
return newConn;
|
||||
}
|
||||
|
||||
- (id) connectionBecameInvalid: (NSNotification*)notification
|
||||
{
|
||||
id connection = [notification object];
|
||||
|
||||
[NSNotificationCenter removeObserver: self
|
||||
name: NSConnectionDidDieNotification
|
||||
object: connection];
|
||||
|
||||
if (connection == conn)
|
||||
{
|
||||
NSLog(@"argh - gdnc server root connection has been destroyed.\n");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMapTable *table;
|
||||
|
||||
/*
|
||||
* Remove all clients registered via this connection
|
||||
* (should normally only be 1) - then the connection.
|
||||
*/
|
||||
table = NSMapGet(connections, connection);
|
||||
if (table)
|
||||
{
|
||||
[self removeObserversForClients: table];
|
||||
NSFreeMapTable(table);
|
||||
}
|
||||
NSMapRemove(connections, connection);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) registerClient: (id<GDNCClient>)client
|
||||
{
|
||||
NSMapTable *table;
|
||||
GDNCClient *info;
|
||||
|
||||
table = NSMapGet(connections, [(NSDistantObject*)client connectionForProxy]);
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"registration with unknown connection"];
|
||||
}
|
||||
if (NSMapGet(table, client) != 0)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"registration with registered client"];
|
||||
}
|
||||
info = [GDNCClient new];
|
||||
info->client = client;
|
||||
NSMapInsert(table, client, info);
|
||||
[info release];
|
||||
}
|
||||
|
||||
- (void) postNotificationName: (NSString*)notificationName
|
||||
object: (NSString*)notificationObject
|
||||
userInfo: (NSData*)d
|
||||
deliverImmediately: (BOOL)deliverImmediately
|
||||
for: (id<GDNCClient>)client
|
||||
{
|
||||
NSMutableArray *observers = [NSMutableArray array];
|
||||
NSMutableArray *byName;
|
||||
NSMutableArray *byObject;
|
||||
unsigned pos;
|
||||
GDNCNotification *notification;
|
||||
|
||||
byName = [observersForNames objectForKey: notificationName];
|
||||
byObject = [observersForObjects objectForKey: notificationObject];
|
||||
/*
|
||||
* Build up a list of all those observers that should get sent this.
|
||||
*/
|
||||
for (pos = [byName count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs = [byName objectAtIndex: pos];
|
||||
|
||||
if (obs->notificationObject == nil ||
|
||||
[obs->notificationObject isEqual: notificationObject])
|
||||
{
|
||||
[observers addObject: obs];
|
||||
}
|
||||
}
|
||||
for (pos = [byObject count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs = [byObject objectAtIndex: pos];
|
||||
|
||||
if (obs->notificationName == nil ||
|
||||
[obs->notificationName isEqual: notificationName])
|
||||
{
|
||||
if ([observers indexOfObjectIdenticalTo: obs] == NSNotFound)
|
||||
{
|
||||
[observers addObject: obs];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build notification object to queue for observer.
|
||||
*/
|
||||
if ([observers count] > 0)
|
||||
{
|
||||
notification = [GDNCNotification notificationWithName: notificationName
|
||||
object: notificationObject
|
||||
data: d];
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the object to the queue for this observer depending on suspension
|
||||
* state of the client NSDistributedNotificationCenter etc.
|
||||
*/
|
||||
for (pos = [observers count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs = [observers objectAtIndex: pos];
|
||||
|
||||
if (obs->client->suspended == NO || deliverImmediately == YES)
|
||||
{
|
||||
[obs->queue addObject: d];
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (obs->behavior)
|
||||
{
|
||||
case NSNotificationSuspensionBehaviorDrop:
|
||||
break;
|
||||
case NSNotificationSuspensionBehaviorCoalesce:
|
||||
[obs->queue removeAllObjects];
|
||||
[obs->queue addObject: d];
|
||||
break;
|
||||
case NSNotificationSuspensionBehaviorHold:
|
||||
[obs->queue addObject: d];
|
||||
break;
|
||||
case NSNotificationSuspensionBehaviorDeliverImmediately:
|
||||
[obs->queue addObject: d];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now perform the actual posting of the notification to the observers in
|
||||
* our array.
|
||||
*/
|
||||
for (pos = [observers count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs = [observers objectAtIndex: pos];
|
||||
|
||||
if (obs->client->suspended == NO || deliverImmediately == YES)
|
||||
{
|
||||
/*
|
||||
* Post notifications to the observer until:
|
||||
* an exception (obs is set to nil)
|
||||
* the queue is empty ([obs->queue count] == 0)
|
||||
* the observer is removed (obs is not in allObservers)
|
||||
*/
|
||||
while (obs != nil && [obs->queue count] > 0 &&
|
||||
NSHashGet(allObservers, obs) != 0)
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
GDNCNotification *n;
|
||||
|
||||
n = [[obs->queue objectAtIndex: 0] retain];
|
||||
[obs->queue removeObjectAtIndex: 0];
|
||||
[obs->client->client postNotificationName: n->name
|
||||
object: n->object
|
||||
userInfo: n->info
|
||||
selector: obs->selector
|
||||
to: obs->observer];
|
||||
[n release];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
[obs release];
|
||||
obs = nil;
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeObserver: (GDNCObserver*)obs
|
||||
{
|
||||
if (obs->notificationObject)
|
||||
{
|
||||
NSMutableArray *objList;
|
||||
|
||||
objList = [observersForObjects objectForKey: obs->notificationObject];
|
||||
if (objList != nil)
|
||||
{
|
||||
[objList removeObject: obs];
|
||||
}
|
||||
}
|
||||
if (obs->notificationName)
|
||||
{
|
||||
NSMutableArray *namList;
|
||||
|
||||
namList = [observersForNames objectForKey: obs->notificationName];
|
||||
if (namList != nil)
|
||||
{
|
||||
[namList removeObject: obs];
|
||||
}
|
||||
}
|
||||
NSHashRemove(allObservers, obs);
|
||||
}
|
||||
|
||||
- (void) removeObserversForClients: (NSMapTable*)clients
|
||||
{
|
||||
NSMapEnumerator enumerator;
|
||||
NSObject *client;
|
||||
GDNCClient *info;
|
||||
|
||||
enumerator = NSEnumerateMapTable(clients);
|
||||
while (NSNextMapEnumeratorPair(&enumerator,
|
||||
(void**)&client, (void**)&info) == YES)
|
||||
{
|
||||
while ([info->observers count] > 0)
|
||||
{
|
||||
[self removeObserver: [info->observers objectAtIndex: 0]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) removeObserver: (unsigned long)anObserver
|
||||
name: (NSString*)notificationName
|
||||
object: (NSString*)notificationObject
|
||||
for: (id<GDNCClient>)client
|
||||
{
|
||||
if (anObserver == 0)
|
||||
{
|
||||
if (notificationName == nil)
|
||||
{
|
||||
NSMutableArray *observers;
|
||||
|
||||
/*
|
||||
* No notification name - so remove all with matching object.
|
||||
*/
|
||||
observers = [observersForObjects objectForKey: notificationObject];
|
||||
while ([observers count] > 0)
|
||||
{
|
||||
GDNCObserver *obs;
|
||||
|
||||
obs = [observers objectAtIndex: 0];
|
||||
[self removeObserver: obs];
|
||||
}
|
||||
}
|
||||
else if (notificationObject == nil)
|
||||
{
|
||||
NSMutableArray *observers;
|
||||
|
||||
/*
|
||||
* No notification object - so remove all with matching name.
|
||||
*/
|
||||
observers = [observersForObjects objectForKey: notificationName];
|
||||
while ([observers count] > 0)
|
||||
{
|
||||
GDNCObserver *obs;
|
||||
|
||||
obs = [observers objectAtIndex: 0];
|
||||
[self removeObserver: obs];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMutableArray *byName;
|
||||
NSMutableArray *byObject;
|
||||
unsigned pos;
|
||||
|
||||
/*
|
||||
* Remove observers that match both name and object.
|
||||
*/
|
||||
byName = [observersForObjects objectForKey: notificationName];
|
||||
byObject = [observersForObjects objectForKey: notificationName];
|
||||
for (pos = [byName count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs;
|
||||
|
||||
obs = [byName objectAtIndex: pos];
|
||||
if ([byObject indexOfObjectIdenticalTo: obs] != NSNotFound)
|
||||
{
|
||||
[self removeObserver: obs];
|
||||
}
|
||||
}
|
||||
for (pos = [byObject count]; pos > 0; pos--)
|
||||
{
|
||||
GDNCObserver *obs;
|
||||
|
||||
obs = [byObject objectAtIndex: pos];
|
||||
if ([byName indexOfObjectIdenticalTo: obs] != NSNotFound)
|
||||
{
|
||||
[self removeObserver: obs];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSMapTable *table;
|
||||
GDNCClient *info;
|
||||
|
||||
/*
|
||||
* If an observer object (as an unsigned) was specified then
|
||||
* the observer MUST be from this client - so we can look
|
||||
* through the per-client list of objects.
|
||||
*/
|
||||
table = NSMapGet(connections,
|
||||
[(NSDistantObject*)client connectionForProxy]);
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"removeObserver with unknown connection"];
|
||||
}
|
||||
info = (GDNCClient*)NSMapGet(table, client);
|
||||
if (info != nil)
|
||||
{
|
||||
unsigned pos = [info->observers count];
|
||||
|
||||
while (pos > 0)
|
||||
{
|
||||
GDNCObserver *obs = [info->observers objectAtIndex: --pos];
|
||||
|
||||
if (obs->observer == anObserver)
|
||||
{
|
||||
if (notificationName == nil ||
|
||||
[notificationName isEqual: obs->notificationName])
|
||||
{
|
||||
if (notificationObject == nil ||
|
||||
[notificationObject isEqual: obs->notificationObject])
|
||||
{
|
||||
[self removeObserver: obs];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setSuspended: (BOOL)flag
|
||||
for: (id<GDNCClient>)client
|
||||
{
|
||||
NSMapTable *table;
|
||||
GDNCClient *info;
|
||||
|
||||
table = NSMapGet(connections, [(NSDistantObject*)client connectionForProxy]);
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"setSuspended: with unknown connection"];
|
||||
}
|
||||
info = (GDNCClient*)NSMapGet(table, client);
|
||||
if (info == nil)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"setSuspended: with unregistered client"];
|
||||
}
|
||||
info->suspended = flag;
|
||||
}
|
||||
|
||||
- (void) unregisterClient: (id<GDNCClient>)client
|
||||
{
|
||||
NSMapTable *table;
|
||||
GDNCClient *info;
|
||||
|
||||
table = NSMapGet(connections, [(NSDistantObject*)client connectionForProxy]);
|
||||
if (table == 0)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"unregistration with unknown connection"];
|
||||
}
|
||||
info = (GDNCClient*)NSMapGet(table, client);
|
||||
if (info == nil)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"unregistration with unregistered client"];
|
||||
}
|
||||
while ([info->observers count] > 0)
|
||||
{
|
||||
[self removeObserver: [info->observers objectAtIndex: 0]];
|
||||
}
|
||||
NSMapRemove(table, client);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
GDNCServer *server;
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
pool = [NSAutoreleasePool new];
|
||||
server = [GDNCServer new];
|
||||
[pool release];
|
||||
if (server != nil)
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue