1996-03-03 02:18:46 +00:00
|
|
|
|
/* Implementation of object for broadcasting Notification objects
|
|
|
|
|
Copyright (C) 1996 Free Software Foundation, Inc.
|
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1996-03-03 02:18:46 +00:00
|
|
|
|
Created: March 1996
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* The implementation for NotificationDispatcher. */
|
|
|
|
|
|
1996-03-12 14:49:02 +00:00
|
|
|
|
/* NeXT says you can only have one NotificationCenter per task;
|
|
|
|
|
I don't think GNU needs this restriction with its corresponding
|
|
|
|
|
NotificationDistributor class. */
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1996-04-17 15:23:00 +00:00
|
|
|
|
#include <gnustep/base/NotificationDispatcher.h>
|
|
|
|
|
#include <gnustep/base/LinkedListNode.h>
|
|
|
|
|
#include <gnustep/base/Array.h>
|
|
|
|
|
#include <gnustep/base/Invocation.h>
|
1998-07-21 17:56:48 +00:00
|
|
|
|
#include <Foundation/NSNotification.h>
|
1996-03-03 02:18:46 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
|
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* NotificationRequest class - One of these objects is created for
|
|
|
|
|
each -addObserver... request. It holds the requested invocation,
|
|
|
|
|
name and object. Each object is placed
|
1996-03-03 02:18:46 +00:00
|
|
|
|
(1) in one LinkedList, as keyed by the NAME/OBJECT parameters (accessible
|
|
|
|
|
through one of the ivars: anonymous_nr_list, object_2_nr_list,
|
|
|
|
|
name_2_nr_list), and
|
|
|
|
|
(2) in the Array, as keyed by the OBSERVER (as accessible through
|
|
|
|
|
the ivar observer_2_nr_array.
|
|
|
|
|
|
|
|
|
|
To post a notification in satisfaction of this request,
|
1996-03-07 00:28:43 +00:00
|
|
|
|
send -postNotification:. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
@interface NotificationRequest : LinkedListNode
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
int _retain_count;
|
|
|
|
|
id _name;
|
|
|
|
|
id _object;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
- initWithName: n object: o;
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (NSString*) notificationName;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
- notificationObject;
|
|
|
|
|
- (void) postNotification: n;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NotificationRequest
|
|
|
|
|
|
|
|
|
|
- initWithName: n object: o
|
|
|
|
|
{
|
|
|
|
|
[super init];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
_retain_count = 0;
|
|
|
|
|
_name = [n retain];
|
|
|
|
|
_object = o;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
/* Note that OBJECT is not retained. See the comment for
|
|
|
|
|
-addObserver... in NotificationDispatcher.h. */
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Implement these retain/release methods here for efficiency, since
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NotificationRequest's get retained and released by all their
|
1996-03-03 02:18:46 +00:00
|
|
|
|
holders. Doing this is a judgement call; I'm choosing speed over
|
|
|
|
|
space. */
|
|
|
|
|
|
|
|
|
|
- retain
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
_retain_count++;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (oneway void) release
|
|
|
|
|
{
|
1997-10-28 14:34:49 +00:00
|
|
|
|
if (_retain_count-- == 0)
|
1996-03-03 02:18:46 +00:00
|
|
|
|
[self dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) retainCount
|
|
|
|
|
{
|
1997-10-28 14:34:49 +00:00
|
|
|
|
return _retain_count + 1;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[_name release];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (BOOL)isEqual:other
|
|
|
|
|
{
|
|
|
|
|
if ([self class] != [other class])
|
|
|
|
|
return NO;
|
|
|
|
|
if (_object != [other notificationObject])
|
|
|
|
|
return NO;
|
|
|
|
|
if (_name != [other notificationName] &&
|
|
|
|
|
![_name isEqual: [other notificationName]])
|
|
|
|
|
return NO;
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (NSString*) notificationName
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
return _name;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- notificationObject
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
return _object;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) postNotification: n
|
|
|
|
|
{
|
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NotificationInvocation : NotificationRequest
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
id _invocation;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
- initWithInvocation: i name: n object: o;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NotificationInvocation
|
|
|
|
|
|
|
|
|
|
- initWithInvocation: i name: n object: o
|
|
|
|
|
{
|
|
|
|
|
[super initWithName: n object: o];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
_invocation = [i retain];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[_invocation release];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) postNotification: n
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[_invocation invokeWithObject: n];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NotificationPerformer : NotificationRequest
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
id _target;
|
|
|
|
|
SEL _selector;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
- initWithTarget: t selector: (SEL)s name: n object: o;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NotificationPerformer
|
|
|
|
|
|
|
|
|
|
- initWithTarget: t selector: (SEL)s name: n object: o
|
|
|
|
|
{
|
|
|
|
|
[super initWithName: n object: o];
|
|
|
|
|
/* Note that TARGET is not retained. See the comment for
|
|
|
|
|
-addObserver... in NotificationDispatcher.h. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
_target = t;
|
|
|
|
|
_selector = s;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) postNotification: n
|
|
|
|
|
{
|
1998-09-28 20:38:02 +00:00
|
|
|
|
[_target performSelector: _selector withObject: n];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NotificationDispatcher
|
|
|
|
|
|
|
|
|
|
/* The default instance, most often the only one created.
|
1996-07-15 18:41:44 +00:00
|
|
|
|
It is accessed by the class methods at the end of this file.
|
|
|
|
|
There is no need to mutex locking of this variable. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
static NotificationDispatcher *default_notification_dispatcher = nil;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NotificationDispatcher class])
|
|
|
|
|
default_notification_dispatcher = [self new];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initializing. */
|
|
|
|
|
|
|
|
|
|
- init
|
|
|
|
|
{
|
|
|
|
|
[super init];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
_anonymous_nr_list = [LinkedList new];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
/* Use NSNonOwnedPointerOrNullMapKeyCallBacks so we won't retain
|
1996-03-07 00:28:43 +00:00
|
|
|
|
the object. We will, however, retain the values, which are
|
|
|
|
|
LinkedList's. */
|
|
|
|
|
_object_2_nr_list =
|
1996-03-03 02:18:46 +00:00
|
|
|
|
NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Use NSObjectMapKeyCallBacks so we retain the NAME. We also retain
|
|
|
|
|
the values, which are LinkedList's. */
|
|
|
|
|
_name_2_nr_list =
|
1997-10-18 19:49:50 +00:00
|
|
|
|
NSCreateMapTable (NSObjectMapKeyCallBacks,
|
1996-03-03 02:18:46 +00:00
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Use NSNonOwnedPointerOrNullMapKeyCallBacks so we won't retain
|
|
|
|
|
the observer. We will, however, retain the values, which are Array's. */
|
|
|
|
|
_observer_2_nr_array =
|
1996-03-03 02:18:46 +00:00
|
|
|
|
NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
_lock = [NSRecursiveLock new];
|
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
[_anonymous_nr_list release];
|
|
|
|
|
NSFreeMapTable( _object_2_nr_list);
|
|
|
|
|
NSFreeMapTable (_name_2_nr_list);
|
|
|
|
|
NSFreeMapTable (_observer_2_nr_array);
|
|
|
|
|
[_lock release];
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
/* Adding new observers. */
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* This is the (private) designated method for adding observers. If we
|
|
|
|
|
came from -addInvocation... then OBSERVER is actually an Invocation. */
|
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
- (void) _addObserver: observer
|
|
|
|
|
notificationRequest: nr
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* If observer is nil, there is nothing to do; return. */
|
|
|
|
|
if (!observer)
|
|
|
|
|
return;
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
[_lock lock];
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Record the notification request in an array keyed by OBSERVER. */
|
|
|
|
|
{
|
|
|
|
|
/* Find the array of all the requests by OBSERVER. */
|
|
|
|
|
Array *nr_array = NSMapGet (_observer_2_nr_array, observer);
|
|
|
|
|
if (!nr_array)
|
|
|
|
|
{
|
|
|
|
|
nr_array = [Array new];
|
|
|
|
|
/* nr_array is retained; observer is not. */
|
|
|
|
|
NSMapInsert (_observer_2_nr_array, observer, nr_array);
|
|
|
|
|
/* Now that nr_array is retained by the map table, release it;
|
|
|
|
|
this way the array will be completely released when the
|
|
|
|
|
map table is done with it. */
|
|
|
|
|
[nr_array release];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* If the observer is already watching this request, do nothing. */
|
|
|
|
|
if ([nr_array containsObject:nr])
|
|
|
|
|
{
|
|
|
|
|
[_lock unlock];
|
|
|
|
|
return;
|
|
|
|
|
}
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[nr_array appendObject: nr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Record the NotificationRequest in one of three MapTable->LinkedLists. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
/* Record the request in one, and only one, LinkedList. The LinkedList
|
|
|
|
|
is stored in a hash table accessed by a key. Which key is used
|
|
|
|
|
depends on what combination of NAME and OBJECT are non-nil. */
|
|
|
|
|
if (!name)
|
|
|
|
|
{
|
|
|
|
|
if (!object)
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* This NotificationRequest will get posted notifications
|
|
|
|
|
for all NAME and OBJECT combinations. */
|
|
|
|
|
[_anonymous_nr_list appendObject: nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
LinkedList *nr_list = NSMapGet (_object_2_nr_list, object);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
if (!nr_list)
|
|
|
|
|
{
|
|
|
|
|
nr_list = [LinkedList new];
|
|
|
|
|
/* nr_list is retained; object is not retained. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NSMapInsert (_object_2_nr_list, object, nr_list);
|
|
|
|
|
/* Now that nr_list is retained by the map table, release it;
|
|
|
|
|
this way the list will be completely released when the
|
|
|
|
|
map table is done with it. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
[nr_list release];
|
|
|
|
|
}
|
|
|
|
|
[nr_list appendObject: nr];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
LinkedList *nr_list = NSMapGet (_name_2_nr_list, name);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
if (!nr_list)
|
|
|
|
|
{
|
|
|
|
|
nr_list = [LinkedList new];
|
|
|
|
|
/* nr_list is retained; object is not retained. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NSMapInsert (_name_2_nr_list, name, nr_list);
|
|
|
|
|
/* Now that nr_list is retained by the map table, release it;
|
|
|
|
|
this way the list will be completely released when the
|
|
|
|
|
map table is done with it. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
[nr_list release];
|
|
|
|
|
}
|
|
|
|
|
[nr_list appendObject: nr];
|
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
|
|
|
|
[_lock unlock];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
- (void) addInvocation: (id <Invoking>)invocation
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-07 00:28:43 +00:00
|
|
|
|
object: object
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
|
|
|
|
id nr;
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Create the NotificationRequest object that will hold this
|
|
|
|
|
observation request. This will retain INVOCATION and NAME. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
nr = [[NotificationInvocation alloc]
|
|
|
|
|
initWithInvocation: invocation
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
|
|
|
|
|
/* Record it in all the right places. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[self _addObserver: invocation
|
1996-03-03 02:18:46 +00:00
|
|
|
|
notificationRequest: nr
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
|
1996-04-17 00:29:24 +00:00
|
|
|
|
/* Since nr was retained when it was added to the Array and
|
|
|
|
|
LinkedList above, we can release it now. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[nr release];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* For those that want to specify a selector instead of an invocation
|
1996-03-07 00:28:43 +00:00
|
|
|
|
as a way to contact the observer. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
- (void) addObserver: observer
|
|
|
|
|
selector: (SEL)sel
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
id nr;
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Create the NotificationRequest object that will hold this
|
|
|
|
|
observation request. This will retain INVOCATION and NAME. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
nr = [[NotificationPerformer alloc]
|
|
|
|
|
initWithTarget: observer
|
|
|
|
|
selector: sel
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
|
|
|
|
|
/* Record it in all the right places. */
|
|
|
|
|
[self _addObserver: observer
|
|
|
|
|
notificationRequest: nr
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
|
1996-04-17 00:29:24 +00:00
|
|
|
|
/* Since nr was retained when it was added to the Array and
|
|
|
|
|
LinkedList above, we can release it now. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[nr release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Removing objects. */
|
|
|
|
|
|
|
|
|
|
/* A private method.
|
|
|
|
|
Remove the NR object from its one LinkedList; if this is the last
|
|
|
|
|
element of that LinkedList, and the LinkedList is map-accessible,
|
|
|
|
|
also release the LinkedList. */
|
|
|
|
|
|
|
|
|
|
- (void) _removeFromLinkedListNotificationRequest: nr
|
|
|
|
|
{
|
|
|
|
|
id nr_list = [nr linkedList];
|
|
|
|
|
|
|
|
|
|
/* See if, instead of removing the NR from its LinkedList, we can
|
|
|
|
|
actually release the entire list. */
|
|
|
|
|
if ([nr_list count] == 1
|
|
|
|
|
&& nr_list != _anonymous_nr_list)
|
|
|
|
|
{
|
|
|
|
|
id nr_name;
|
|
|
|
|
id nr_object;
|
|
|
|
|
LinkedList *mapped_nr_list;
|
|
|
|
|
|
|
|
|
|
assert ([nr_list firstObject] == nr);
|
|
|
|
|
if ((nr_name = [nr notificationName]))
|
|
|
|
|
{
|
|
|
|
|
mapped_nr_list = NSMapGet (_name_2_nr_list, nr_name);
|
|
|
|
|
assert (mapped_nr_list == nr_list);
|
|
|
|
|
NSMapRemove (_name_2_nr_list, nr_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nr_object = [nr notificationObject];
|
|
|
|
|
assert (nr_object);
|
|
|
|
|
mapped_nr_list = NSMapGet (_object_2_nr_list, nr_object);
|
|
|
|
|
assert (mapped_nr_list == nr_list);
|
|
|
|
|
NSMapRemove (_object_2_nr_list, nr_object);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
[nr_list removeObject: nr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Removing notification requests. */
|
|
|
|
|
|
|
|
|
|
/* Remove all notification requests that would be sent to INVOCATION. */
|
|
|
|
|
|
|
|
|
|
- (void) removeInvocation: invocation
|
|
|
|
|
{
|
|
|
|
|
[self removeObserver: invocation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove the notification requests matching NAME and OBJECT that
|
|
|
|
|
would be sent to INVOCATION. As with adding an observation
|
|
|
|
|
request, nil NAME or OBJECT act as wildcards. */
|
|
|
|
|
|
|
|
|
|
- (void) removeInvocation: invocation
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-07 00:28:43 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
[self removeObserver: invocation
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
/* Remove all records pertaining to OBSERVER. For instance, this
|
|
|
|
|
should be called before the OBSERVER is -dealloc'ed. */
|
|
|
|
|
|
|
|
|
|
- (void) removeObserver: observer
|
|
|
|
|
{
|
|
|
|
|
Array *observer_nr_array;
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NotificationRequest *nr;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* If OBSERVER is nil, do nothing; just return. NOTE: This *does not*
|
|
|
|
|
remove all requests with a nil OBSERVER; it would be too easy to
|
|
|
|
|
unintentionally remove other's requests that way. If you need to
|
|
|
|
|
remove a request with a nil OBSERVER, use -removeObserver:name:object: */
|
|
|
|
|
if (!observer)
|
|
|
|
|
return;
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
[_lock lock];
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Get the array of NotificationRequest's associated with OBSERVER. */
|
|
|
|
|
observer_nr_array = NSMapGet (_observer_2_nr_array, observer);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
if (!observer_nr_array)
|
|
|
|
|
/* OBSERVER was never registered for any notification requests with us.
|
|
|
|
|
Nothing to do. */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Remove each of these from it's LinkedList. */
|
|
|
|
|
FOR_ARRAY (observer_nr_array, nr)
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[self _removeFromLinkedListNotificationRequest: nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
END_FOR_ARRAY (observer_nr_array);
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Remove from the MapTable the list of NotificationRequest's
|
1996-03-03 02:18:46 +00:00
|
|
|
|
associated with OBSERVER. This also releases the observer_nr_array,
|
|
|
|
|
and its contents. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NSMapRemove (_observer_2_nr_array, observer);
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
|
|
|
|
[_lock unlock];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove the notification requests for the given parameters. As with
|
|
|
|
|
adding an observation request, nil NAME or OBJECT act as wildcards. */
|
|
|
|
|
|
|
|
|
|
- (void) removeObserver: observer
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
Array *observer_nr_array;
|
1996-03-07 00:28:43 +00:00
|
|
|
|
|
|
|
|
|
/* If both NAME and OBJECT are nil, this call is the same as
|
|
|
|
|
-removeObserver:, so just call it. */
|
|
|
|
|
if (!name && !object)
|
|
|
|
|
[self removeObserver: observer];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* We are now guaranteed that at least one of NAME and OBJECT is non-nil. */
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
[_lock lock];
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Get the list of NotificationRequest's associated with OBSERVER. */
|
|
|
|
|
observer_nr_array = NSMapGet (_observer_2_nr_array, observer);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
if (!observer_nr_array)
|
|
|
|
|
/* OBSERVER was never registered for any notification requests with us.
|
|
|
|
|
Nothing to do. */
|
|
|
|
|
return;
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* Find those NotificationRequest's from the array that
|
1996-03-03 02:18:46 +00:00
|
|
|
|
match NAME and OBJECT, and remove them from the array and
|
|
|
|
|
their linked list. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
/* xxx If we thought the LinkedList from the map table keyed on NAME
|
|
|
|
|
would be shorter, we could use that instead. */
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
NotificationRequest *nr;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
int count = [observer_nr_array count];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = count-1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
nr = [observer_nr_array objectAtIndex: i];
|
|
|
|
|
if ((!name || [name isEqual: [nr notificationName]])
|
|
|
|
|
&& (!object || [object isEqual: [nr notificationObject]]))
|
|
|
|
|
{
|
|
|
|
|
/* We can remove from the array, even though we are "enumerating"
|
|
|
|
|
over it, because we are enumerating from back-to-front,
|
|
|
|
|
and the indices of yet-to-come objects don't change when
|
|
|
|
|
high-indexed objects are removed. */
|
|
|
|
|
[observer_nr_array removeObjectAtIndex: i];
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[self _removeFromLinkedListNotificationRequest: nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* xxx If there are some LinkedList's that are empty, I should
|
|
|
|
|
remove them from the map table's. */
|
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
|
|
|
|
[_lock unlock];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. */
|
|
|
|
|
|
|
|
|
|
- (void) postNotification: notification
|
|
|
|
|
{
|
1998-07-28 17:51:55 +00:00
|
|
|
|
id notification_name = [(NSNotification *)notification name];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
id notification_object = [notification object];
|
|
|
|
|
id nr;
|
|
|
|
|
LinkedList *nr_list;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSMutableArray* array;
|
1996-03-03 02:18:46 +00:00
|
|
|
|
|
|
|
|
|
/* Make sure the notification has a name. */
|
|
|
|
|
if (!notification_name)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"Tried to post a notification with no name."];
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
[_lock lock];
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
array = [[NSMutableArray arrayWithCapacity:10] retain];
|
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
/* Post the notification to all the observers that specified neither
|
|
|
|
|
NAME or OBJECT. */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
if ([_anonymous_nr_list count])
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
FOR_COLLECTION (_anonymous_nr_list, nr)
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[array addObject:nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
1996-03-07 00:28:43 +00:00
|
|
|
|
END_FOR_COLLECTION (_anonymous_nr_list);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
while ([array count] > 0)
|
|
|
|
|
{
|
|
|
|
|
nr = [array objectAtIndex:0];
|
|
|
|
|
|
|
|
|
|
if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */
|
|
|
|
|
[nr postNotification:notification];
|
|
|
|
|
[array removeObjectAtIndex:0];
|
|
|
|
|
}
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Post the notification to all the observers that specified OBJECT,
|
|
|
|
|
but didn't specify NAME. */
|
|
|
|
|
if (notification_object)
|
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
nr_list = NSMapGet (_object_2_nr_list, notification_object);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
if (nr_list)
|
|
|
|
|
{
|
|
|
|
|
FOR_COLLECTION (nr_list, nr)
|
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[array addObject:nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
END_FOR_COLLECTION (nr_list);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
while ([array count] > 0)
|
|
|
|
|
{
|
|
|
|
|
nr = [array objectAtIndex:0];
|
|
|
|
|
|
|
|
|
|
if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */
|
|
|
|
|
[nr postNotification:notification];
|
|
|
|
|
[array removeObjectAtIndex:0];
|
|
|
|
|
}
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Post the notification to all the observers of NAME; (and if the
|
|
|
|
|
observer's OBJECT is non-nil, don't send unless the observer's OBJECT
|
|
|
|
|
matches the notification's OBJECT). */
|
1996-03-07 00:28:43 +00:00
|
|
|
|
nr_list = NSMapGet (_name_2_nr_list, notification_name);
|
1996-03-03 02:18:46 +00:00
|
|
|
|
if (nr_list)
|
|
|
|
|
{
|
|
|
|
|
FOR_COLLECTION (nr_list, nr)
|
|
|
|
|
{
|
|
|
|
|
id nr_object = [nr notificationObject];
|
|
|
|
|
if (!nr_object || nr_object == notification_object)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[array addObject:nr];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
END_FOR_COLLECTION (nr_list);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
while ([array count] > 0)
|
|
|
|
|
{
|
|
|
|
|
nr = [array objectAtIndex:0];
|
|
|
|
|
|
|
|
|
|
if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */
|
|
|
|
|
[nr postNotification:notification];
|
|
|
|
|
[array removeObjectAtIndex:0];
|
|
|
|
|
}
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[array release];
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
[_lock unlock];
|
1996-03-03 02:18:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (void) postNotificationName: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
1998-07-21 17:56:48 +00:00
|
|
|
|
[self postNotification: [NSNotification notificationWithName: name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object]];
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
- (void) postNotificationName: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
userInfo: info
|
|
|
|
|
{
|
1998-07-21 17:56:48 +00:00
|
|
|
|
[self postNotification: [NSNotification notificationWithName: name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
userInfo: info]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Class methods. */
|
|
|
|
|
|
1996-03-12 14:49:02 +00:00
|
|
|
|
+ defaultInstance
|
|
|
|
|
{
|
|
|
|
|
return default_notification_dispatcher;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
+ (void) addInvocation: (id <Invoking>)invocation
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-07 00:28:43 +00:00
|
|
|
|
object: object
|
1996-03-03 02:18:46 +00:00
|
|
|
|
{
|
1996-03-07 00:28:43 +00:00
|
|
|
|
[default_notification_dispatcher addInvocation: invocation
|
1996-03-03 02:18:46 +00:00
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) addObserver: observer
|
|
|
|
|
selector: (SEL)sel
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher addObserver: observer
|
|
|
|
|
selector: sel
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-07 00:28:43 +00:00
|
|
|
|
+ (void) removeInvocation: invocation
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher removeInvocation: invocation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) removeInvocation: invocation
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-07 00:28:43 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher removeInvocation: invocation
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-03 02:18:46 +00:00
|
|
|
|
+ (void) removeObserver: observer
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher removeObserver: observer];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) removeObserver: observer
|
1996-11-24 17:30:39 +00:00
|
|
|
|
name: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher removeObserver: observer
|
|
|
|
|
name: name
|
|
|
|
|
object: object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) postNotification: notification
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher postNotification: notification];
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
+ (void) postNotificationName: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher postNotificationName: name
|
|
|
|
|
object: object];
|
|
|
|
|
}
|
|
|
|
|
|
1996-11-24 17:30:39 +00:00
|
|
|
|
+ (void) postNotificationName: (NSString*)name
|
1996-03-03 02:18:46 +00:00
|
|
|
|
object: object
|
|
|
|
|
userInfo: info
|
|
|
|
|
{
|
|
|
|
|
[default_notification_dispatcher postNotificationName: name
|
|
|
|
|
object: object
|
|
|
|
|
userInfo: info];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NotificationDispatcher (OpenStepCompat)
|
|
|
|
|
|
|
|
|
|
/* For OpenStep compatibility. */
|
|
|
|
|
+ defaultCenter
|
|
|
|
|
{
|
|
|
|
|
return default_notification_dispatcher;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|