1997-09-01 21:59:51 +00:00
|
|
|
|
/* Implementation of object for waiting on several input sources
|
|
|
|
|
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Original by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Created: March 1996
|
|
|
|
|
OPENSTEP version by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Created: August 1997
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1996-04-10 18:20:36 +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.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
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.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* October 1996 - extensions to permit file descriptors to be watched
|
|
|
|
|
for being readable or writable added by Richard Frith-Macdonald
|
|
|
|
|
(richard@brainstorm.co.uk) */
|
|
|
|
|
|
|
|
|
|
/* Andrews original comments - may still be valid even now -
|
|
|
|
|
|
|
|
|
|
Does it strike anyone else that NSNotificationCenter,
|
|
|
|
|
NSNotificationQueue, NSNotification, NSRunLoop, the "notifications"
|
|
|
|
|
a run loop sends the objects on which it is listening, NSEvent, and
|
|
|
|
|
the event queue maintained by NSApplication are all much more
|
|
|
|
|
intertwined/similar than OpenStep gives them credit for?
|
|
|
|
|
|
|
|
|
|
I wonder if these classes could be re-organized a little to make a
|
|
|
|
|
more uniform, "grand-unified" mechanism for: events,
|
|
|
|
|
event-listening, event-queuing, and event-distributing. It could
|
|
|
|
|
be quite pretty.
|
|
|
|
|
|
|
|
|
|
(GNUstep would definitely provide classes that were compatible with
|
|
|
|
|
all these OpenStep classes, but those classes could be wrappers
|
|
|
|
|
around fundamentally cleaner GNU classes. RMS has advised using an
|
|
|
|
|
underlying organization/implementation different from NeXT's
|
|
|
|
|
whenever that makes sense---it helps legally distinguish our work.)
|
|
|
|
|
|
|
|
|
|
Thoughts and insights, anyone?
|
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1996-04-17 15:34:35 +00:00
|
|
|
|
#include <gnustep/base/preface.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <gnustep/base/Heap.h>
|
|
|
|
|
#include <Foundation/NSMapTable.h>
|
|
|
|
|
#include <Foundation/NSDate.h>
|
|
|
|
|
#include <Foundation/NSValue.h>
|
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
|
|
|
|
#include <Foundation/NSPort.h>
|
|
|
|
|
#include <Foundation/NSTimer.h>
|
|
|
|
|
#include <Foundation/NSNotificationQueue.h>
|
1996-04-10 18:20:36 +00:00
|
|
|
|
#include <Foundation/NSRunLoop.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSThread.h>
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#ifndef __WIN32__
|
1998-07-21 17:56:48 +00:00
|
|
|
|
#include <time.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#endif /* !__WIN32__ */
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <string.h> /* for memset() */
|
|
|
|
|
|
|
|
|
|
/* On some systems FD_ZERO is a macro that uses bzero().
|
|
|
|
|
Just define it to use memset(). */
|
|
|
|
|
#define bzero(PTR, LEN) memset (PTR, 0, LEN)
|
|
|
|
|
|
|
|
|
|
static int debug_run_loop = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The 'RunLoopWatcher' class was written to permit the (relatively)
|
|
|
|
|
* easy addition of new events to be watched for in the runloop.
|
|
|
|
|
*
|
|
|
|
|
* To add a new type of event, the 'RunLoopEventType' enumeration must be
|
|
|
|
|
* extended, and the methods must be modified to handle the new type.
|
|
|
|
|
*
|
|
|
|
|
* The internal variables if the RunLoopWatcher are used as follows -
|
|
|
|
|
* If 'invalidated' is set, the wather should be disabled and should
|
|
|
|
|
* be removed from the runloop when next encountered.
|
|
|
|
|
*
|
|
|
|
|
* The 'data' variable is used to identify the resource/event that the
|
|
|
|
|
* watcher is interested in.
|
|
|
|
|
*
|
|
|
|
|
* The 'receiver' is the object which should be told when the event
|
|
|
|
|
* occurs. This object is retained so that we know it will continue
|
|
|
|
|
* to exist and can handle a callback.
|
|
|
|
|
*
|
|
|
|
|
* The 'type' variable indentifies the type of event watched for.
|
|
|
|
|
* NSRunLoops [-acceptInputForMode:beforeDate:] method MUST contain
|
|
|
|
|
* code to watch for events of each type.
|
|
|
|
|
*
|
|
|
|
|
* The 'limit' variable contains a date after which the event is useless
|
|
|
|
|
* and the watcher can be removed from the runloop. If this is nil
|
|
|
|
|
* then the watcher will only be removed if explicitly requested.
|
|
|
|
|
*
|
|
|
|
|
* To set this variable, the method adding the RunLoopWatcher to the
|
|
|
|
|
* runloop must ask the 'receiver' (or its delegate) to supply a date
|
|
|
|
|
* using the '[-limitDateForMode:]' message.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@interface RunLoopWatcher: NSObject
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
BOOL invalidated;
|
|
|
|
|
void *data;
|
|
|
|
|
id receiver;
|
|
|
|
|
RunLoopEventType type;
|
|
|
|
|
NSDate *limit;
|
|
|
|
|
unsigned count;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) eventFor: (void*)info
|
|
|
|
|
mode: (NSString*)mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (void*) getData;
|
|
|
|
|
- (NSDate*) getLimit;
|
|
|
|
|
- (id) getReceiver;
|
|
|
|
|
- (RunLoopEventType) getType;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (BOOL) decrement;
|
|
|
|
|
- (void) increment;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- initWithType: (RunLoopEventType)type
|
|
|
|
|
receiver: (id)anObj
|
|
|
|
|
data: (void*)data;
|
|
|
|
|
- (void) invalidate;
|
|
|
|
|
- (BOOL) isValid;
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) setData: (void*)item;
|
|
|
|
|
- (void) setLimit: (NSDate*)when;
|
|
|
|
|
- (void) setReceiver: (id)anObj;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation RunLoopWatcher
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[self invalidate];
|
|
|
|
|
[limit release];
|
|
|
|
|
[receiver release];
|
|
|
|
|
[super dealloc];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (BOOL) decrement
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
count--;
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return NO;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) eventFor: (void*)info
|
|
|
|
|
mode: (NSString*)mode
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
return;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([receiver respondsToSelector:
|
|
|
|
|
@selector(receivedEvent:type:extra:forMode:)])
|
|
|
|
|
{
|
|
|
|
|
[receiver receivedEvent: data type: type extra: info forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case ET_RDESC:
|
|
|
|
|
case ET_RPORT:
|
|
|
|
|
[receiver readyForReadingOnFileDescriptor: (int)info];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ET_WDESC:
|
|
|
|
|
[receiver readyForWritingOnFileDescriptor: (int)info];
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void*) getData
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return data;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDate*) getLimit
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return limit;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) getReceiver
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return receiver;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (RunLoopEventType) getType
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return type;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (void) increment
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
count++;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- initWithType: (RunLoopEventType)aType
|
|
|
|
|
receiver: (id)anObj
|
|
|
|
|
data: (void*)item
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
invalidated = NO;
|
|
|
|
|
switch (aType)
|
|
|
|
|
{
|
|
|
|
|
case ET_RDESC: type = aType; break;
|
|
|
|
|
case ET_WDESC: type = aType; break;
|
|
|
|
|
case ET_RPORT: type = aType; break;
|
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"NSRunLoop - unknown event type"];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[self setReceiver: anObj];
|
|
|
|
|
[self setData: item];
|
|
|
|
|
[self setLimit: nil];
|
|
|
|
|
count = 0;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) invalidate
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
invalidated = YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isValid
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (invalidated == YES)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([receiver respondsToSelector: @selector(isValid)] &&
|
|
|
|
|
[receiver isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setData: (void*)item
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
data = item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setLimit: (NSDate*)when
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSDate* d = [when retain];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[limit release];
|
|
|
|
|
limit = d;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) setReceiver: (id)anObject
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
id obj = receiver;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
receiver = [anObject retain];
|
1997-09-09 15:30:24 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[obj release];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1998-04-02 14:27:40 +00:00
|
|
|
|
|
|
|
|
|
@interface NSRunLoop (TimedPerformers)
|
|
|
|
|
- (NSMutableArray*) _timedPerformers;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (TimedPerformers)
|
|
|
|
|
- (NSMutableArray*) _timedPerformers
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return _timedPerformers;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* The RunLoopPerformer class is used to hold information about
|
|
|
|
|
* messages which are due to be sent to objects once a particular
|
|
|
|
|
* runloop iteration has passed.
|
|
|
|
|
*/
|
|
|
|
|
@interface RunLoopPerformer: NSObject
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
SEL selector;
|
|
|
|
|
id target;
|
|
|
|
|
id argument;
|
|
|
|
|
unsigned order;
|
|
|
|
|
NSArray *modes;
|
|
|
|
|
NSTimer *timer;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) fire;
|
|
|
|
|
- initWithSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)target
|
|
|
|
|
argument: (id)argument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
order: (unsigned int)order
|
|
|
|
|
modes: (NSArray*)modes;
|
|
|
|
|
- (BOOL) matchesSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (NSArray*) modes;
|
|
|
|
|
- (unsigned int) order;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (void) setTimer: (NSTimer*)timer;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation RunLoopPerformer
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[timer invalidate];
|
|
|
|
|
[target release];
|
|
|
|
|
[argument release];
|
|
|
|
|
[modes release];
|
|
|
|
|
[super dealloc];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
- (void) fire
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (timer != nil)
|
|
|
|
|
{
|
|
|
|
|
timer = nil;
|
|
|
|
|
[[self retain] autorelease];
|
|
|
|
|
[[[NSRunLoop currentInstance] _timedPerformers]
|
1998-04-02 14:27:40 +00:00
|
|
|
|
removeObjectIdenticalTo: self];
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[target performSelector: selector withObject: argument];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- initWithSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
order: (unsigned int)theOrder
|
|
|
|
|
modes: (NSArray*)theModes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
selector = aSelector;
|
|
|
|
|
target = [aTarget retain];
|
|
|
|
|
argument = [anArgument retain];
|
|
|
|
|
order = theOrder;
|
|
|
|
|
modes = [theModes copy];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) matchesSelector: (SEL)aSelector
|
1998-10-29 08:46:30 +00:00
|
|
|
|
target: (id)aTarget
|
|
|
|
|
argument: (id)anArgument
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (selector == aSelector)
|
|
|
|
|
{
|
|
|
|
|
if (target == aTarget)
|
|
|
|
|
{
|
|
|
|
|
if ([argument isEqual:anArgument])
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return modes;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned int) order
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return order;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (void) setTimer: (NSTimer*)t
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
timer = t;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (TimedPerformers)
|
|
|
|
|
|
|
|
|
|
+ (void) cancelPreviousPerformRequestsWithTarget: (id)target
|
|
|
|
|
selector: (SEL)aSelector
|
|
|
|
|
object: (id)arg
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
[target retain];
|
|
|
|
|
[arg retain];
|
|
|
|
|
array = [[NSRunLoop currentInstance] _timedPerformers];
|
|
|
|
|
for (i = [array count]; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if ([[array objectAtIndex: i-1] matchesSelector: aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: arg])
|
|
|
|
|
{
|
|
|
|
|
[array removeObjectAtIndex: i-1];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[arg release];
|
|
|
|
|
[target release];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
withObject: (id)argument
|
|
|
|
|
afterDelay: (NSTimeInterval)seconds
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
|
|
|
|
|
array = [[NSRunLoop currentInstance] _timedPerformers];
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: self
|
|
|
|
|
argument: argument
|
|
|
|
|
order: 0
|
|
|
|
|
modes: nil];
|
|
|
|
|
[array addObject: item];
|
|
|
|
|
[item setTimer: [NSTimer scheduledTimerWithTimeInterval: seconds
|
|
|
|
|
target: item
|
|
|
|
|
selector: @selector(fire)
|
|
|
|
|
userInfo: nil
|
|
|
|
|
repeats: NO]];
|
|
|
|
|
[item release];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
withObject: (id)argument
|
|
|
|
|
afterDelay: (NSTimeInterval)seconds
|
|
|
|
|
inModes: (NSArray*)modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSRunLoop *loop;
|
|
|
|
|
NSMutableArray *array;
|
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
NSTimer *timer;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (modes == nil || [modes count] == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
loop = [NSRunLoop currentInstance];
|
|
|
|
|
array = [loop _timedPerformers];
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: self
|
|
|
|
|
argument: argument
|
|
|
|
|
order: 0
|
|
|
|
|
modes: nil];
|
|
|
|
|
[array addObject: item];
|
|
|
|
|
timer = [NSTimer timerWithTimeInterval: seconds
|
|
|
|
|
target: item
|
|
|
|
|
selector: @selector(fire)
|
|
|
|
|
userInfo: nil
|
|
|
|
|
repeats: NO];
|
|
|
|
|
[item setTimer: timer];
|
|
|
|
|
[item release];
|
|
|
|
|
for (i = 0; i < [modes count]; i++)
|
|
|
|
|
{
|
|
|
|
|
[loop addTimer: timer forMode: [modes objectAtIndex: i]];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NSRunLoop (Private)
|
|
|
|
|
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (void) _addWatcher: (RunLoopWatcher*)item
|
|
|
|
|
forMode: (NSString*)mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (void) _checkPerformers;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (RunLoopWatcher*) _getWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode;
|
1998-04-02 14:27:40 +00:00
|
|
|
|
- (NSMutableArray*) _performers;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
- (void) _removeWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (Private)
|
|
|
|
|
|
|
|
|
|
/* Add a watcher to the list for the specified mode. Keep the list in
|
|
|
|
|
limit-date order. */
|
|
|
|
|
- (void) _addWatcher: (RunLoopWatcher*) item forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *watchers;
|
|
|
|
|
id obj;
|
|
|
|
|
NSDate *limit;
|
|
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
watchers = NSMapGet (_mode_2_watchers, mode);
|
|
|
|
|
if (watchers == nil)
|
|
|
|
|
{
|
|
|
|
|
watchers = [NSMutableArray new];
|
|
|
|
|
NSMapInsert (_mode_2_watchers, mode, watchers);
|
|
|
|
|
[watchers release];
|
|
|
|
|
count = 0;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
count = [watchers count];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If the receiver or its delegate (if any) respond to
|
|
|
|
|
* 'limitDateForMode:' then we ask them for the limit date for
|
|
|
|
|
* this watcher.
|
|
|
|
|
*/
|
|
|
|
|
obj = [item getReceiver];
|
|
|
|
|
if ([obj respondsToSelector: @selector(limitDateForMode:)])
|
|
|
|
|
{
|
|
|
|
|
[item setLimit: [obj limitDateForMode:mode]];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else if ([obj respondsToSelector: @selector(delegate)])
|
|
|
|
|
{
|
|
|
|
|
obj = [obj delegate];
|
|
|
|
|
if ([obj respondsToSelector: @selector(limitDateForMode:)])
|
|
|
|
|
{
|
|
|
|
|
[item setLimit: [obj limitDateForMode:mode]];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
limit = [item getLimit];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* Make sure that the items in the watchers list are ordered.
|
|
|
|
|
*/
|
|
|
|
|
if (limit == nil || count == 0)
|
|
|
|
|
{
|
|
|
|
|
[watchers addObject:item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
NSDate* when = [[watchers objectAtIndex:i] getLimit];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (when == nil || [limit earlierDate:when] == when)
|
|
|
|
|
{
|
|
|
|
|
[watchers insertObject:item atIndex:i];
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (i == count)
|
|
|
|
|
{
|
|
|
|
|
[watchers addObject:item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _checkPerformers
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
NSArray *array = [NSArray arrayWithArray: _performers];
|
|
|
|
|
int count = [array count];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
item = (RunLoopPerformer*)[array objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
pos = [_performers indexOfObjectIdenticalTo: item];
|
|
|
|
|
if (pos != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
if ([[item modes] containsObject: _current_mode])
|
|
|
|
|
{
|
|
|
|
|
[_performers removeObjectAtIndex: pos];
|
|
|
|
|
[item fire];
|
1998-04-02 14:27:40 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop(GNUstepExtensions)
|
|
|
|
|
|
|
|
|
|
+ currentInstance
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self currentRunLoop];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) currentMode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] currentMode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) run
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] run];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) runUntilDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) runUntilDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[NSRunLoop currentRunLoop] runUntilDate: date forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] runOnceBeforeDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [[NSRunLoop currentRunLoop] runOnceBeforeDate: date forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
watcher: (id<RunLoopEvents>)watcher
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopWatcher *info;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
info = [self _getWatcher: data type: type forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (info && [info getReceiver] == (id)watcher)
|
|
|
|
|
{
|
|
|
|
|
/* Increment usage count for this watcher. */
|
|
|
|
|
[info increment];
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Remove any existing handler for another watcher. */
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
|
|
|
|
|
|
|
|
|
/* Create new object to hold information. */
|
|
|
|
|
info = [[RunLoopWatcher alloc] initWithType: type
|
|
|
|
|
receiver: watcher
|
|
|
|
|
data: data];
|
|
|
|
|
/* Add the object to the array for the mode and keep count. */
|
|
|
|
|
[self _addWatcher:info forMode:mode];
|
|
|
|
|
[info increment];
|
|
|
|
|
|
|
|
|
|
[info release]; /* Now held in array. */
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addReadDescriptor: (int)fd
|
|
|
|
|
object: (id <FdListening>)listener
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)fd
|
|
|
|
|
type: ET_RDESC
|
|
|
|
|
watcher: (id<RunLoopEvents>)listener
|
|
|
|
|
forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add our new handler information to the array. */
|
|
|
|
|
- (void) addWriteDescriptor: (int)fd
|
|
|
|
|
object: (id <FdSpeaking>)speaker
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)fd
|
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: (id<RunLoopEvents>)speaker
|
|
|
|
|
forMode: mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
1997-09-09 15:30:24 +00:00
|
|
|
|
all: (BOOL)removeAll
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (removeAll)
|
|
|
|
|
{
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RunLoopWatcher *info;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
info = [self _getWatcher: data type: type forMode: mode];
|
1997-09-09 15:30:24 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (info && [info decrement] == NO)
|
|
|
|
|
{
|
|
|
|
|
[self _removeWatcher: data type: type forMode: mode];
|
1997-09-09 15:30:24 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeReadDescriptor: (int)fd
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self removeEvent:(void*)fd type: ET_RDESC forMode:mode all:NO];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeWriteDescriptor: (int)fd
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self removeEvent:(void*)fd type: ET_WDESC forMode:mode all:NO];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) runOnceBeforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self runOnceBeforeDate: date forMode: _current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Running the run loop once through for timers and input listening. */
|
|
|
|
|
|
|
|
|
|
- (BOOL) runOnceBeforeDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self runMode:mode beforeDate:date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) runUntilDate: date forMode: (NSString*)mode
|
|
|
|
|
{
|
|
|
|
|
volatile double ti;
|
1998-03-05 00:37:44 +00:00
|
|
|
|
BOOL mayDoMore = YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
ti = [date timeIntervalSinceNow];
|
|
|
|
|
/* Positive values are in the future. */
|
1998-03-05 00:37:44 +00:00
|
|
|
|
while (ti > 0 && mayDoMore == YES)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
id arp = [NSAutoreleasePool new];
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop run until date %f seconds from now\n", ti);
|
1998-03-05 00:37:44 +00:00
|
|
|
|
mayDoMore = [self runMode: mode beforeDate: date];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[arp release];
|
|
|
|
|
ti = [date timeIntervalSinceNow];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1996-04-10 18:20:36 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
+ currentRunLoop
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
static NSString *key = @"NSRunLoopThreadKey";
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSRunLoop* r;
|
|
|
|
|
NSThread* t;
|
|
|
|
|
|
|
|
|
|
t = [NSThread currentThread];
|
1998-10-29 08:46:30 +00:00
|
|
|
|
r = [[t threadDictionary] objectForKey: key];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (r == nil)
|
|
|
|
|
{
|
|
|
|
|
r = [NSRunLoop new];
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[[t threadDictionary] setObject: r forKey: key];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[r release];
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
1996-04-10 18:20:36 +00:00
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSRunLoop class])
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[self currentRunLoop];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is the designated initializer. */
|
|
|
|
|
- init
|
|
|
|
|
{
|
|
|
|
|
[super init];
|
|
|
|
|
_current_mode = NSDefaultRunLoopMode;
|
|
|
|
|
_mode_2_timers = NSCreateMapTable (NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
_mode_2_watchers = NSCreateMapTable (NSObjectMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
1998-09-10 04:48:50 +00:00
|
|
|
|
_performers = [[NSMutableArray alloc] initWithCapacity:8];
|
|
|
|
|
_timedPerformers = [[NSMutableArray alloc] initWithCapacity:8];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return self;
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (void) dealloc
|
1996-04-10 18:20:36 +00:00
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSFreeMapTable(_mode_2_timers);
|
|
|
|
|
NSFreeMapTable(_mode_2_watchers);
|
|
|
|
|
[_performers release];
|
|
|
|
|
[_timedPerformers release];
|
|
|
|
|
[super dealloc];
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
- (NSString*) currentMode
|
|
|
|
|
{
|
|
|
|
|
return _current_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Adding timers. They are removed when they are invalid. */
|
|
|
|
|
|
|
|
|
|
- (void) addTimer: timer
|
|
|
|
|
forMode: (NSString*)mode
|
1996-04-10 18:20:36 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
Heap *timers;
|
|
|
|
|
|
|
|
|
|
timers = NSMapGet (_mode_2_timers, mode);
|
|
|
|
|
if (!timers)
|
|
|
|
|
{
|
|
|
|
|
timers = [Heap new];
|
|
|
|
|
NSMapInsert (_mode_2_timers, mode, timers);
|
|
|
|
|
[timers release];
|
|
|
|
|
}
|
|
|
|
|
/* xxx Should we make sure it isn't already there? */
|
|
|
|
|
[timers addObject: timer];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fire appropriate timers and determine the earliest time that anything
|
|
|
|
|
watched for becomes useless. */
|
|
|
|
|
|
|
|
|
|
- limitDateForMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
id saved_mode;
|
|
|
|
|
Heap *timers;
|
|
|
|
|
NSTimer *min_timer = nil;
|
|
|
|
|
RunLoopWatcher *min_watcher = nil;
|
|
|
|
|
NSArray *watchers;
|
|
|
|
|
NSDate *when;
|
|
|
|
|
|
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
|
|
|
|
timers = NSMapGet(_mode_2_timers, mode);
|
|
|
|
|
if (timers)
|
|
|
|
|
{
|
|
|
|
|
while ((min_timer = [timers minObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if (![min_timer isValid])
|
|
|
|
|
{
|
|
|
|
|
[timers removeFirstObject];
|
|
|
|
|
min_timer = nil;
|
|
|
|
|
continue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([[min_timer fireDate] timeIntervalSinceNow] > 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[min_timer retain];
|
|
|
|
|
[timers removeFirstObject];
|
|
|
|
|
/* Firing will also increment its fireDate, if it is repeating. */
|
|
|
|
|
[min_timer fire];
|
|
|
|
|
if ([min_timer isValid])
|
|
|
|
|
{
|
|
|
|
|
[timers addObject: min_timer];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[min_timer release];
|
|
|
|
|
min_timer = nil;
|
|
|
|
|
[NSNotificationQueue runLoopASAP]; /* Post notifications. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Is this right? At the moment we invalidate and discard watchers
|
|
|
|
|
whose limit-dates have passed. */
|
|
|
|
|
watchers = NSMapGet(_mode_2_watchers, mode);
|
|
|
|
|
if (watchers)
|
|
|
|
|
{
|
|
|
|
|
while ([watchers count] > 0)
|
|
|
|
|
{
|
|
|
|
|
min_watcher = (RunLoopWatcher*)[watchers objectAtIndex:0];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (![min_watcher isValid])
|
|
|
|
|
{
|
|
|
|
|
[watchers removeObjectAtIndex:0];
|
|
|
|
|
min_watcher = nil;
|
|
|
|
|
continue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
when = [min_watcher getLimit];
|
|
|
|
|
if (when == nil || [when timeIntervalSinceNow] > 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id obj;
|
|
|
|
|
NSDate *nxt = nil;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the receiver or its delegate wants to know about
|
|
|
|
|
* timeouts - inform it and give it a chance to set a
|
|
|
|
|
* revised limit date.
|
|
|
|
|
*/
|
|
|
|
|
obj = [min_watcher getReceiver];
|
|
|
|
|
if ([obj respondsToSelector:
|
|
|
|
|
@selector(timedOutEvent:type:forMode:)])
|
|
|
|
|
{
|
|
|
|
|
nxt = [obj timedOutEvent:[min_watcher getData]
|
|
|
|
|
type:[min_watcher getType]
|
|
|
|
|
forMode:_current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else if ([obj respondsToSelector:@selector(delegate)])
|
|
|
|
|
{
|
|
|
|
|
obj = [obj delegate];
|
|
|
|
|
if ([obj respondsToSelector:
|
|
|
|
|
@selector(timedOutEvent:type:forMode:)])
|
|
|
|
|
{
|
|
|
|
|
nxt = [obj timedOutEvent:[min_watcher getData]
|
|
|
|
|
type:[min_watcher getType]
|
|
|
|
|
forMode:_current_mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (nxt && [nxt timeIntervalSinceNow] > 0.0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the watcher has been given a revised limit date -
|
|
|
|
|
* re-insert it into the queue in the correct place.
|
|
|
|
|
*/
|
|
|
|
|
[min_watcher retain];
|
|
|
|
|
[min_watcher setLimit:nxt];
|
|
|
|
|
[watchers removeObjectAtIndex:0];
|
|
|
|
|
[self _addWatcher:min_watcher forMode:mode];
|
|
|
|
|
[min_watcher release];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the watcher is now useless - invalidate it and
|
|
|
|
|
* remove it from the queue so that we don't need to
|
|
|
|
|
* check it again.
|
|
|
|
|
*/
|
|
|
|
|
[min_watcher invalidate];
|
|
|
|
|
[watchers removeObjectAtIndex:0];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
min_watcher = nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If there are timers - set limit date to the earliest of them.
|
|
|
|
|
*/
|
|
|
|
|
if (min_timer)
|
|
|
|
|
{
|
|
|
|
|
when = [min_timer fireDate];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
when = nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If there are watchers, set the limit date to that of the earliest
|
|
|
|
|
* watcher (or leave it as the date of the earliest timer if that is
|
|
|
|
|
* before the watchers limit).
|
|
|
|
|
* NB. A watcher without a limit date watches forever - so it's limit
|
|
|
|
|
* is effectively some time in the distant future.
|
|
|
|
|
*/
|
|
|
|
|
if (min_watcher)
|
|
|
|
|
{
|
|
|
|
|
NSDate* lim;
|
|
|
|
|
|
|
|
|
|
if ([min_watcher getLimit] == nil) /* No limit for watcher */
|
|
|
|
|
{
|
|
|
|
|
lim = [NSDate distantFuture]; /* - watches forever. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lim = [min_watcher getLimit];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (when == nil)
|
|
|
|
|
{
|
|
|
|
|
when = lim;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
when = [when earlierDate:lim];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* 'when' will only be nil if there are neither timers nor watchers
|
|
|
|
|
* outstanding.
|
|
|
|
|
*/
|
|
|
|
|
if (when && debug_run_loop)
|
|
|
|
|
{
|
|
|
|
|
printf ("\tNSRunLoop limit date %f\n",
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[when timeIntervalSinceReferenceDate]);
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
_current_mode = saved_mode;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return when;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-09-12 17:54:10 +00:00
|
|
|
|
- (RunLoopWatcher*) _getWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSArray *watchers;
|
|
|
|
|
RunLoopWatcher *info;
|
|
|
|
|
int count;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
watchers = NSMapGet (_mode_2_watchers, mode);
|
|
|
|
|
if (watchers == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (count = 0; count < [watchers count]; count++)
|
|
|
|
|
{
|
|
|
|
|
info = [watchers objectAtIndex: count];
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([info getType] == type)
|
|
|
|
|
{
|
|
|
|
|
if ([info getData] == data)
|
|
|
|
|
{
|
|
|
|
|
return info;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return nil;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _removeWatcher: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
NSMutableArray *watchers;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (mode == nil)
|
|
|
|
|
{
|
|
|
|
|
mode = _current_mode;
|
|
|
|
|
}
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
watchers = NSMapGet (_mode_2_watchers, mode);
|
|
|
|
|
if (watchers)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = [watchers count]; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
RunLoopWatcher* info;
|
1997-09-12 17:54:10 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
info = (RunLoopWatcher*)[watchers objectAtIndex:(i-1)];
|
|
|
|
|
if ([info getType] == type && [info getData] == data)
|
|
|
|
|
{
|
|
|
|
|
[info invalidate];
|
|
|
|
|
[watchers removeObject: info];
|
1997-09-12 17:54:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* Listen to input sources.
|
|
|
|
|
If LIMIT_DATE is nil, then don't wait; i.e. call select() with 0 timeout */
|
|
|
|
|
|
|
|
|
|
- (void) acceptInputForMode: (NSString*)mode
|
|
|
|
|
beforeDate: limit_date
|
|
|
|
|
{
|
|
|
|
|
NSTimeInterval ti;
|
|
|
|
|
struct timeval timeout;
|
|
|
|
|
void *select_timeout;
|
|
|
|
|
fd_set fds; /* The file descriptors we will listen to. */
|
|
|
|
|
fd_set read_fds; /* Copy for listening to read-ready fds. */
|
|
|
|
|
fd_set exception_fds; /* Copy for listening to exception fds. */
|
|
|
|
|
fd_set write_fds; /* Copy for listening for write-ready fds. */
|
|
|
|
|
int select_return;
|
|
|
|
|
int fd_index;
|
|
|
|
|
NSMapTable *rfd_2_object;
|
|
|
|
|
NSMapTable *wfd_2_object;
|
|
|
|
|
id saved_mode;
|
|
|
|
|
int num_inputs = 0;
|
|
|
|
|
|
|
|
|
|
assert (mode);
|
|
|
|
|
saved_mode = _current_mode;
|
|
|
|
|
_current_mode = mode;
|
|
|
|
|
|
|
|
|
|
/* Find out how much time we should wait, and set SELECT_TIMEOUT. */
|
|
|
|
|
if (!limit_date)
|
|
|
|
|
{
|
|
|
|
|
/* Don't wait at all. */
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
}
|
|
|
|
|
else if ((ti = [limit_date timeIntervalSinceNow]) < LONG_MAX
|
|
|
|
|
&& ti > 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* Wait until the LIMIT_DATE. */
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop accept input before %f (seconds from now %f)\n",
|
|
|
|
|
[limit_date timeIntervalSinceReferenceDate], ti);
|
|
|
|
|
/* If LIMIT_DATE has already past, return immediately. */
|
|
|
|
|
if (ti < 0)
|
|
|
|
|
{
|
|
|
|
|
[self _checkPerformers];
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop limit date past, returning\n");
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
timeout.tv_sec = ti;
|
|
|
|
|
timeout.tv_usec = (ti - timeout.tv_sec) * 1000000.0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
}
|
|
|
|
|
else if (ti <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* The LIMIT_DATE has already past; return immediately without
|
|
|
|
|
polling any inputs. */
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Wait forever. */
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop accept input waiting forever\n");
|
|
|
|
|
select_timeout = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get ready to listen to file descriptors.
|
|
|
|
|
Initialize the set of FDS we'll pass to select(), and create
|
|
|
|
|
an empty map for keeping track of which object is associated
|
|
|
|
|
with which file descriptor. */
|
|
|
|
|
FD_ZERO (&fds);
|
|
|
|
|
FD_ZERO (&write_fds);
|
|
|
|
|
rfd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
wfd_2_object = NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
|
|
|
|
/* Do the pre-listening set-up for the file descriptors of this mode. */
|
|
|
|
|
{
|
1997-09-09 15:30:24 +00:00
|
|
|
|
NSArray *watchers;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
watchers = NSMapGet (_mode_2_watchers, mode);
|
|
|
|
|
if (watchers) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = [watchers count]; i > 0; i--) {
|
|
|
|
|
RunLoopWatcher* info = [watchers objectAtIndex:(i-1)];
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
if ([info isValid] == NO) {
|
|
|
|
|
[watchers removeObjectAtIndex:(i-1)];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
switch ([info getType]) {
|
|
|
|
|
case ET_WDESC:
|
|
|
|
|
fd = (int)[info getData];
|
|
|
|
|
FD_SET (fd, &write_fds);
|
|
|
|
|
NSMapInsert (wfd_2_object, (void*)fd, info);
|
|
|
|
|
num_inputs++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ET_RDESC:
|
|
|
|
|
fd = (int)[info getData];
|
|
|
|
|
FD_SET (fd, &fds);
|
|
|
|
|
NSMapInsert (rfd_2_object, (void*)fd, info);
|
|
|
|
|
num_inputs++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ET_RPORT:
|
|
|
|
|
{
|
|
|
|
|
id port = [info getReceiver];
|
|
|
|
|
int port_fd_count = 128; // xxx #define this constant
|
|
|
|
|
int port_fd_array[port_fd_count];
|
|
|
|
|
|
|
|
|
|
if ([port respondsTo: @selector(getFds:count:)])
|
|
|
|
|
[port getFds: port_fd_array count: &port_fd_count];
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf("\tNSRunLoop listening to %d sockets\n",
|
|
|
|
|
port_fd_count);
|
|
|
|
|
|
|
|
|
|
while (port_fd_count--)
|
|
|
|
|
{
|
|
|
|
|
FD_SET (port_fd_array[port_fd_count], &fds);
|
|
|
|
|
NSMapInsert (rfd_2_object,
|
|
|
|
|
(void*)port_fd_array[port_fd_count],
|
|
|
|
|
info);
|
|
|
|
|
num_inputs++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait for incoming data, listening to the file descriptors in _FDS. */
|
|
|
|
|
read_fds = fds;
|
|
|
|
|
exception_fds = fds;
|
|
|
|
|
|
|
|
|
|
/* Detect if the NSRunLoop is idle, and if necessary - dispatch the
|
|
|
|
|
notifications from NSNotificationQueue's idle queue? */
|
|
|
|
|
if (num_inputs == 0 && [NSNotificationQueue runLoopMore])
|
|
|
|
|
{
|
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
|
timeout.tv_usec = 0;
|
|
|
|
|
select_timeout = &timeout;
|
|
|
|
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
|
|
|
|
select_timeout);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
select_return = select (FD_SETSIZE, &read_fds, &write_fds, &exception_fds,
|
|
|
|
|
select_timeout);
|
|
|
|
|
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
printf ("\tNSRunLoop select returned %d\n", select_return);
|
|
|
|
|
|
|
|
|
|
if (select_return < 0)
|
|
|
|
|
{
|
|
|
|
|
/* Some exceptional condition happened. */
|
|
|
|
|
/* xxx We can do something with exception_fds, instead of
|
|
|
|
|
aborting here. */
|
|
|
|
|
perror ("[TcpInPort receivePacketWithTimeout:] select()");
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
else if (select_return == 0)
|
|
|
|
|
{
|
|
|
|
|
NSFreeMapTable (rfd_2_object);
|
|
|
|
|
NSFreeMapTable (wfd_2_object);
|
|
|
|
|
[NSNotificationQueue runLoopIdle];
|
|
|
|
|
[self _checkPerformers];
|
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Look at all the file descriptors select() says are ready for reading;
|
|
|
|
|
notify the corresponding object for each of the ready fd's. */
|
|
|
|
|
for (fd_index = 0; fd_index < FD_SETSIZE; fd_index++)
|
|
|
|
|
{
|
|
|
|
|
if (FD_ISSET (fd_index, &write_fds))
|
|
|
|
|
{
|
|
|
|
|
id watcher = (id) NSMapGet (wfd_2_object, (void*)fd_index);
|
|
|
|
|
assert (watcher);
|
|
|
|
|
[watcher eventFor:(void*)fd_index mode:_current_mode];
|
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET (fd_index, &read_fds))
|
|
|
|
|
{
|
|
|
|
|
id watcher = (id) NSMapGet (rfd_2_object, (void*)fd_index);
|
|
|
|
|
assert (watcher);
|
|
|
|
|
[watcher eventFor:(void*)fd_index mode:_current_mode];
|
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Clean up before returning. */
|
|
|
|
|
NSFreeMapTable (rfd_2_object);
|
|
|
|
|
NSFreeMapTable (wfd_2_object);
|
|
|
|
|
|
|
|
|
|
[self _checkPerformers];
|
1998-02-03 14:20:00 +00:00
|
|
|
|
[NSNotificationQueue runLoopASAP];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
_current_mode = saved_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) runMode: (NSString*)mode beforeDate: date
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
id d;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* If date has already passed, simply return. */
|
|
|
|
|
if ([date timeIntervalSinceNow] < 0)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
{
|
|
|
|
|
printf ("\tNSRunLoop run mode with date already past\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Find out how long we can wait before first limit date. */
|
|
|
|
|
d = [self limitDateForMode: mode];
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
if (debug_run_loop)
|
|
|
|
|
{
|
|
|
|
|
printf ("\tNSRunLoop run mode with nothing to do\n");
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return NO;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Use the earlier of the two dates we have. */
|
|
|
|
|
d = [[d earlierDate:date] retain];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
/* Wait, listening to our input sources. */
|
|
|
|
|
[self acceptInputForMode: mode beforeDate: d];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[d release];
|
|
|
|
|
return YES;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) run
|
|
|
|
|
{
|
|
|
|
|
[self runUntilDate: [NSDate distantFuture]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) runUntilDate: date
|
|
|
|
|
{
|
|
|
|
|
[self runUntilDate: date forMode: _current_mode];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* NSRunLoop mode strings. */
|
|
|
|
|
|
|
|
|
|
id NSDefaultRunLoopMode = @"NSDefaultRunLoopMode";
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSRunLoop (OPENSTEP)
|
|
|
|
|
|
|
|
|
|
- (void) addPort: (NSPort*)port
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self addEvent: (void*)port
|
|
|
|
|
type: ET_RPORT
|
|
|
|
|
watcher: (id<RunLoopEvents>)port
|
|
|
|
|
forMode: (NSString*)mode];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) cancelPerformSelector: (SEL)aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
int count = [_performers count];
|
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[target retain];
|
|
|
|
|
[argument retain];
|
|
|
|
|
for (i = count; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
item = (RunLoopPerformer*)[_performers objectAtIndex:(i-1)];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if ([item matchesSelector:aSelector target:target argument:argument])
|
|
|
|
|
{
|
|
|
|
|
[_performers removeObjectAtIndex:(i-1)];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[argument release];
|
|
|
|
|
[target release];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) configureAsServer
|
|
|
|
|
{
|
|
|
|
|
/* Nothing to do here */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) performSelector: (SEL)aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
order: (unsigned int)order
|
|
|
|
|
modes: (NSArray*)modes
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
RunLoopPerformer *item;
|
|
|
|
|
int count = [_performers count];
|
|
|
|
|
|
|
|
|
|
item = [[RunLoopPerformer alloc] initWithSelector: aSelector
|
|
|
|
|
target: target
|
|
|
|
|
argument: argument
|
|
|
|
|
order: order
|
|
|
|
|
modes: modes];
|
|
|
|
|
/* Add new item to list - reverse ordering */
|
|
|
|
|
if (count == 0)
|
|
|
|
|
{
|
|
|
|
|
[_performers addObject:item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1998-10-29 08:46:30 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
if ([[_performers objectAtIndex:i] order] <= order)
|
|
|
|
|
{
|
|
|
|
|
[_performers insertObject:item atIndex:i];
|
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
if (i == count)
|
|
|
|
|
{
|
|
|
|
|
[_performers addObject:item];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-29 08:46:30 +00:00
|
|
|
|
[item release];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removePort: (NSPort*)port
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
1998-10-29 08:46:30 +00:00
|
|
|
|
return [self removeEvent:(void*)port type: ET_RPORT forMode:mode all:NO];
|
1996-04-10 18:20:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|