2001-12-17 14:31:42 +00:00
|
|
|
/** Implementation of NSTimer for GNUstep
|
1999-06-03 12:36:10 +00:00
|
|
|
Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1996-03-12 15:39:13 +00:00
|
|
|
Created: March 1996
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2001-12-17 14:31:42 +00:00
|
|
|
Rewrite by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-03-12 15:39:13 +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.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
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.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1996-03-12 15:39:13 +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
|
2005-05-22 03:32:16 +00:00
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
<title>NSTimer class reference</title>
|
|
|
|
$Date$ $Revision$
|
1996-03-12 15:39:13 +00:00
|
|
|
*/
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
#include "config.h"
|
|
|
|
#include "Foundation/NSTimer.h"
|
|
|
|
#include "Foundation/NSDate.h"
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
#include "Foundation/NSRunLoop.h"
|
|
|
|
#include "Foundation/NSInvocation.h"
|
1996-03-12 15:39:13 +00:00
|
|
|
|
1999-09-14 10:03:02 +00:00
|
|
|
@class NSGDate;
|
2005-07-08 11:48:37 +00:00
|
|
|
@interface NSGDate : NSObject // Help the compiler
|
|
|
|
@end
|
1999-09-14 10:03:02 +00:00
|
|
|
static Class NSDate_class;
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
/**
|
|
|
|
* An <code>NSTimer</code> provides a way to send a message at some time in
|
|
|
|
* the future, possibly repeating every time a fixed interval has passed. To
|
|
|
|
* use a timer, you can either create one that will automatically be added to
|
|
|
|
* the run loop in the current thread (using the -addTimer:forMode: method),
|
|
|
|
* or you can create it without adding it then add it to an [NSRunLoop]
|
|
|
|
* explicitly later.
|
|
|
|
*/
|
1996-03-12 15:39:13 +00:00
|
|
|
@implementation NSTimer
|
|
|
|
|
1999-09-14 10:03:02 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSTimer class])
|
|
|
|
{
|
|
|
|
NSDate_class = [NSGDate class];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-02-03 17:21:20 +00:00
|
|
|
/**
|
2002-01-16 14:00:59 +00:00
|
|
|
* <init />
|
2002-08-27 13:40:42 +00:00
|
|
|
* Initialise the receive, a newly allocated NSTimer object.<br />
|
|
|
|
* The fd argument specifies an initial fire date ... if it is not
|
|
|
|
* supplied (a nil object) then the ti argument is used to create
|
2002-08-27 14:32:27 +00:00
|
|
|
* a start date relative to the current time.<br />
|
2002-08-27 13:40:42 +00:00
|
|
|
* The ti argument specifies the time (in seconds) between the firing.
|
|
|
|
* If it is less than or equal to 0.0 then a small interval is chosen
|
|
|
|
* automatically.<br />
|
|
|
|
* The f argument specifies whether the timer will fire repeatedly
|
|
|
|
* or just once.<br />
|
|
|
|
* If the selector argument is zero, then then object is an invocation
|
|
|
|
* to be used when the timer fires. otherwise, the object is sent the
|
|
|
|
* message specified by the selector and with the timer as an argument.<br />
|
|
|
|
* The fd, object and info arguments will be retained until the timer is
|
2002-06-17 06:47:28 +00:00
|
|
|
* invalidated.<br />
|
2002-01-16 14:00:59 +00:00
|
|
|
*/
|
2002-08-27 13:40:42 +00:00
|
|
|
- (id) initWithFireDate: (NSDate*)fd
|
|
|
|
interval: (NSTimeInterval)ti
|
|
|
|
target: (id)object
|
|
|
|
selector: (SEL)selector
|
|
|
|
userInfo: (id)info
|
|
|
|
repeats: (BOOL)f
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
2002-02-03 17:21:20 +00:00
|
|
|
if (ti <= 0)
|
2000-08-07 22:00:31 +00:00
|
|
|
{
|
2002-02-03 17:21:20 +00:00
|
|
|
ti = 0.0001;
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
2002-02-03 17:21:20 +00:00
|
|
|
_interval = ti;
|
2002-08-27 13:40:42 +00:00
|
|
|
if (fd == nil)
|
|
|
|
{
|
|
|
|
_date = [[NSDate_class allocWithZone: NSDefaultMallocZone()]
|
2002-08-27 16:31:08 +00:00
|
|
|
initWithTimeIntervalSinceNow: _interval];
|
2002-08-27 13:40:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_date = [fd copy];
|
|
|
|
}
|
2002-06-17 06:30:32 +00:00
|
|
|
_target = RETAIN(object);
|
2002-02-03 17:21:20 +00:00
|
|
|
_selector = selector;
|
2002-06-17 06:30:32 +00:00
|
|
|
_info = RETAIN(info);
|
1996-03-12 15:39:13 +00:00
|
|
|
_repeats = f;
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2003-04-17 06:20:17 +00:00
|
|
|
* Create a timer which will fire after ti seconds and, if f is YES,
|
2002-06-17 06:47:28 +00:00
|
|
|
* every ti seconds thereafter. On firing, invocation will be performed.<br />
|
|
|
|
* NB. To make the timer operate, you must add it to a run loop.
|
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
|
2000-08-07 22:00:31 +00:00
|
|
|
invocation: (NSInvocation*)invocation
|
1999-06-03 12:36:10 +00:00
|
|
|
repeats: (BOOL)f
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
2002-08-27 13:40:42 +00:00
|
|
|
return AUTORELEASE([[self alloc] initWithFireDate: nil
|
|
|
|
interval: ti
|
|
|
|
target: invocation
|
|
|
|
selector: NULL
|
|
|
|
userInfo: nil
|
|
|
|
repeats: f]);
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
* Create a timer which will fire after ti seconds and, if f is YES,
|
2002-06-17 06:47:28 +00:00
|
|
|
* every ti seconds thereafter. On firing, the target object will be
|
2003-04-17 06:20:17 +00:00
|
|
|
* sent a message specified by selector and with the value info as an
|
2002-06-17 06:47:28 +00:00
|
|
|
* argument.<br />
|
|
|
|
* NB. To make the timer operate, you must add it to a run loop.
|
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
+ (NSTimer*) timerWithTimeInterval: (NSTimeInterval)ti
|
2000-08-07 22:00:31 +00:00
|
|
|
target: (id)object
|
1999-06-03 12:36:10 +00:00
|
|
|
selector: (SEL)selector
|
2000-08-07 22:00:31 +00:00
|
|
|
userInfo: (id)info
|
1999-06-03 12:36:10 +00:00
|
|
|
repeats: (BOOL)f
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
2002-08-27 13:40:42 +00:00
|
|
|
return AUTORELEASE([[self alloc] initWithFireDate: nil
|
|
|
|
interval: ti
|
|
|
|
target: object
|
|
|
|
selector: selector
|
|
|
|
userInfo: info
|
|
|
|
repeats: f]);
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2002-08-27 13:40:42 +00:00
|
|
|
* Create a timer which will fire after ti seconds and, if f is YES,
|
2002-06-17 06:47:28 +00:00
|
|
|
* every ti seconds thereafter. On firing, invocation will be performed.<br />
|
|
|
|
* This timer will automatically be added to the current run loop and
|
2002-08-27 13:40:42 +00:00
|
|
|
* will fire in the default run loop mode.
|
2002-06-17 06:47:28 +00:00
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
+ (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
|
2000-08-07 22:00:31 +00:00
|
|
|
invocation: (NSInvocation*)invocation
|
1999-06-03 12:36:10 +00:00
|
|
|
repeats: (BOOL)f
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
|
|
|
id t = [self timerWithTimeInterval: ti
|
2002-08-27 16:31:08 +00:00
|
|
|
invocation: invocation
|
|
|
|
repeats: f];
|
1997-09-01 21:59:51 +00:00
|
|
|
[[NSRunLoop currentRunLoop] addTimer: t forMode: NSDefaultRunLoopMode];
|
1996-03-12 15:39:13 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2002-08-27 13:40:42 +00:00
|
|
|
* Create a timer which will fire after ti seconds and, if f is YES,
|
2002-06-17 06:47:28 +00:00
|
|
|
* every ti seconds thereafter. On firing, the target object will be
|
|
|
|
* sent a message specified by selector and with the object info as an
|
|
|
|
* argument.<br />
|
|
|
|
* This timer will automatically be added to the current run loop and
|
2002-08-27 13:40:42 +00:00
|
|
|
* will fire in the default run loop mode.
|
2002-06-17 06:47:28 +00:00
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
+ (NSTimer*) scheduledTimerWithTimeInterval: (NSTimeInterval)ti
|
2000-08-07 22:00:31 +00:00
|
|
|
target: (id)object
|
1999-06-03 12:36:10 +00:00
|
|
|
selector: (SEL)selector
|
2000-08-07 22:00:31 +00:00
|
|
|
userInfo: (id)info
|
1999-06-03 12:36:10 +00:00
|
|
|
repeats: (BOOL)f
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
|
|
|
id t = [self timerWithTimeInterval: ti
|
2000-08-07 22:00:31 +00:00
|
|
|
target: object
|
|
|
|
selector: selector
|
|
|
|
userInfo: info
|
|
|
|
repeats: f];
|
1997-09-01 21:59:51 +00:00
|
|
|
[[NSRunLoop currentRunLoop] addTimer: t forMode: NSDefaultRunLoopMode];
|
1996-03-12 15:39:13 +00:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
2002-06-17 06:30:32 +00:00
|
|
|
if (_invalidated == NO)
|
|
|
|
{
|
|
|
|
[self invalidate];
|
|
|
|
}
|
1999-04-22 11:24:57 +00:00
|
|
|
RELEASE(_date);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
1996-03-12 15:39:13 +00:00
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
* Fires the timer ... either performs an invocation or sends a message
|
2002-06-17 06:47:28 +00:00
|
|
|
* to a target object, depending on how the timer was set up.<br />
|
2006-04-09 16:16:07 +00:00
|
|
|
* If the timer is not set to repeat, it is automatically invalidated.<br />
|
|
|
|
* Exceptions raised during firing of the timer are caught and logged.
|
2002-06-17 06:47:28 +00:00
|
|
|
*/
|
1996-03-12 15:39:13 +00:00
|
|
|
- (void) fire
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
if (_selector == 0)
|
|
|
|
{
|
2004-09-07 16:54:16 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
[(NSInvocation*)_target invoke];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
|
|
|
|
@"raised during posting of timer with target %p and selector '%@'",
|
|
|
|
[localException name], [localException reason], _target,
|
|
|
|
NSStringFromSelector([_target selector]));
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
1996-03-12 15:39:13 +00:00
|
|
|
else
|
2000-08-07 22:00:31 +00:00
|
|
|
{
|
2004-09-07 16:54:16 +00:00
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
[_target performSelector: _selector withObject: self];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
2005-02-22 11:22:44 +00:00
|
|
|
{
|
2004-09-07 16:54:16 +00:00
|
|
|
NSLog(@"*** NSTimer ignoring exception '%@' (reason '%@') "
|
|
|
|
@"raised during posting of timer with target %p and selector '%@'",
|
|
|
|
[localException name], [localException reason], _target,
|
|
|
|
NSStringFromSelector(_selector));
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
1996-03-12 15:39:13 +00:00
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
if (_repeats == NO)
|
|
|
|
{
|
|
|
|
[self invalidate];
|
|
|
|
}
|
|
|
|
else if (_invalidated == NO)
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
2002-11-01 08:11:46 +00:00
|
|
|
extern NSTimeInterval GSTimeNow();
|
1999-04-20 16:28:04 +00:00
|
|
|
NSTimeInterval now = GSTimeNow();
|
1999-04-22 11:24:57 +00:00
|
|
|
NSTimeInterval nxt = [_date timeIntervalSinceReferenceDate];
|
1999-04-20 16:28:04 +00:00
|
|
|
int inc = -1;
|
|
|
|
|
1999-04-22 11:24:57 +00:00
|
|
|
while (nxt <= now) // xxx remove this
|
1999-04-20 16:28:04 +00:00
|
|
|
{
|
|
|
|
inc++;
|
1999-04-22 11:24:57 +00:00
|
|
|
nxt += _interval;
|
1999-04-20 16:28:04 +00:00
|
|
|
}
|
|
|
|
#ifdef LOG_MISSED
|
|
|
|
if (inc > 0)
|
2000-08-07 22:00:31 +00:00
|
|
|
{
|
|
|
|
NSLog(@"Missed %d timeouts at %f second intervals", inc, _interval);
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
#endif
|
1999-04-22 11:24:57 +00:00
|
|
|
RELEASE(_date);
|
2002-08-27 13:40:42 +00:00
|
|
|
_date = [[NSDate_class allocWithZone: NSDefaultMallocZone()]
|
1999-04-22 11:24:57 +00:00
|
|
|
initWithTimeIntervalSinceReferenceDate: nxt];
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
|
|
|
* Marks the timer as invalid, causing its target/invocation and user info
|
|
|
|
* objects to be released.<br />
|
|
|
|
* Invalidated timers are automatically removed from the run loop when it
|
|
|
|
* detects them.
|
|
|
|
*/
|
1996-03-12 15:39:13 +00:00
|
|
|
- (void) invalidate
|
|
|
|
{
|
2002-06-17 06:30:32 +00:00
|
|
|
if (_target != nil)
|
|
|
|
{
|
|
|
|
DESTROY(_target);
|
|
|
|
}
|
|
|
|
if (_info != nil)
|
|
|
|
{
|
|
|
|
DESTROY(_info);
|
|
|
|
}
|
2000-06-27 03:28:00 +00:00
|
|
|
/* OPENSTEP allows this method to be called multiple times. */
|
|
|
|
//NSAssert(_invalidated == NO, NSInternalInconsistencyException);
|
1999-04-20 16:28:04 +00:00
|
|
|
_invalidated = YES;
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
|
|
|
* Checks to see if the timer has been invalidated.
|
|
|
|
*/
|
1996-03-12 15:39:13 +00:00
|
|
|
- (BOOL) isValid
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
if (_invalidated == NO)
|
2002-06-17 06:30:32 +00:00
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
2000-08-07 22:00:31 +00:00
|
|
|
else
|
2002-06-17 06:30:32 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
|
|
|
* Returns the date/time at which the timer is next due to fire.
|
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
- (NSDate*) fireDate
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
1999-04-22 11:24:57 +00:00
|
|
|
return _date;
|
1996-03-12 15:39:13 +00:00
|
|
|
}
|
|
|
|
|
2002-08-27 13:40:42 +00:00
|
|
|
/**
|
|
|
|
* Change the fire date for the receiver.<br />
|
|
|
|
* NB. You should <em>NOT</em> use this method for a timer which has
|
2002-08-27 14:32:27 +00:00
|
|
|
* been added to a run loop. The only time when it is safe to modify
|
2002-08-27 13:40:42 +00:00
|
|
|
* the fire date of a timer in a run loop is for a repeating timer
|
|
|
|
* when the timer is actually in the process of firing.
|
|
|
|
*/
|
|
|
|
- (void) setFireDate: (NSDate*)fireDate
|
|
|
|
{
|
|
|
|
ASSIGN(_date, fireDate);
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
* Returns the interval between firings.
|
2002-06-17 06:47:28 +00:00
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
- (NSTimeInterval) timeInterval
|
|
|
|
{
|
|
|
|
return _interval;
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
|
|
|
* Returns the user info which was set for the timer when it was created,
|
|
|
|
* or nil if none was set or the timer is invalid.
|
|
|
|
*/
|
1999-06-03 12:36:10 +00:00
|
|
|
- (id) userInfo
|
1996-03-12 15:39:13 +00:00
|
|
|
{
|
|
|
|
return _info;
|
|
|
|
}
|
|
|
|
|
2002-06-17 06:47:28 +00:00
|
|
|
/**
|
|
|
|
* Compares timers based on the date at which they should next fire.
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
- (NSComparisonResult) compare: (id)anotherTimer
|
1997-01-11 21:35:35 +00:00
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
if (anotherTimer == self)
|
|
|
|
{
|
|
|
|
return NSOrderedSame;
|
|
|
|
}
|
|
|
|
else if (anotherTimer == nil)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"nil argument for compare:"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-07-08 11:48:37 +00:00
|
|
|
return [_date compare: ((NSTimer*)anotherTimer)->_date];
|
2000-08-07 22:00:31 +00:00
|
|
|
}
|
|
|
|
return 0;
|
1997-01-11 21:35:35 +00:00
|
|
|
}
|
1999-04-22 11:24:57 +00:00
|
|
|
|
1996-03-12 15:39:13 +00:00
|
|
|
@end
|