From 1b066331168a3cd43fa5014e7b0c5134a90fcea6 Mon Sep 17 00:00:00 2001 From: Nick Takayama Date: Tue, 28 Oct 2008 00:09:09 +0900 Subject: [PATCH] adding CPTimer (now with updated @imports) Signed-off-by: Nick Takayama --- Foundation/CPRunLoop.j | 72 +++++++++++++++++ Foundation/CPTimer.j | 195 +++++++++++++++++++++++++++++++++++++++++++++++ Foundation/Foundation.j | 1 + 3 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 Foundation/CPTimer.j diff --git a/Foundation/CPRunLoop.j b/Foundation/CPRunLoop.j index ed3da77..95388f1 100644 --- a/Foundation/CPRunLoop.j +++ b/Foundation/CPRunLoop.j @@ -135,6 +135,9 @@ var _CPRunLoopPerformPool = [], CPArray _queuedPerforms; CPArray _orderedPerforms; BOOL _isPerformingSelectors; + CPArray _timers; //should be a dictionary to allow lookups by mode + id _intervalHandle; + BOOL _isExaminingTimers; } /* @@ -156,6 +159,7 @@ var _CPRunLoopPerformPool = [], { _queuedPerforms = []; _orderedPerforms = []; + _timers = []; } return self; @@ -258,4 +262,72 @@ var _CPRunLoopPerformPool = [], _queuedPerforms = []; } +/*! + Registers a given timer with a given input mode. +*/ +- (void)addTimer:(CPTimer)aTimer forMode:(CPString)mode +{ + _timers.push(aTimer); + + [self limitDateForMode:mode]; +} + +/*! + Performs one pass through the run loop in the specified mode and returns the date at which the next timer is scheduled to fire. +*/ +- (CPDate)limitDateForMode:(CPString)mode +{ + //simple locking to try to prevent concurrent iterating over timers + if (_isExaminingTimers) + return; + + _isExaminingTimers = YES; + + var index = _timers.length, + nextFireDate = nil; + + //cancel existing window.setTimeout + if (_intervalHandle != nil) + window.clearTimeout(_intervalHandle); + + while (index--) + { + var timer = _timers[index]; + + //prune out invalid timers + if (![timer isValid]) + _timers.splice(index, 1); + else + { + //fire any valid timers that need to fire + if ([[timer fireDate] compare:[CPDate date]] != CPOrderedDescending) + [timer fire]; + + //now check the next fire date + if (nextFireDate == nil) + nextFireDate = [timer fireDate]; + else + nextFireDate = [nextFireDate earlierDate:[timer fireDate]]; + } + } + + //initiate a new window.setTimeout if there are any timers + if (nextFireDate != nil) + { + var scheduleIntervalMillisec = [nextFireDate timeIntervalSinceNow] * 1000; + + //in case we have taken too long to process and the next timer should fire already + //schedule a one millisecond timer to call back to this method and repeat the process + if (scheduleIntervalMillisec <= 0) + scheduleIntervalMillisec = 1; + + _intervalHandle = window.setTimeout(function() {[self limitDateForMode:mode]}, scheduleIntervalMillisec); + } + + //unlock + _isExaminingTimers = NO; + + return nextFireDate; +} + @end \ No newline at end of file diff --git a/Foundation/CPTimer.j b/Foundation/CPTimer.j new file mode 100644 index 0000000..3aab767 --- /dev/null +++ b/Foundation/CPTimer.j @@ -0,0 +1,195 @@ +/* + * CPTimer.j + * Foundation + * + * Created by Nick Takayama. + * Copyright 2008. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +import "CPObject.j" +import "CPInvocation.j" +import "CPDate.j" +import "CPRunLoop.j" + +@implementation CPTimer : CPObject +{ + CPTimeInterval _timeInterval; + CPInvocation _invocation; + BOOL _repeats; + BOOL _isValid; + CPDate _fireDate; + id _target; + SEL _selector; + id _userInfo; +} + +/*! + Returns a new NSTimer object and adds it to the current NSRunLoop object in the default mode. +*/ ++(CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)invocation repeats:(BOOL)repeats +{ + var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:invocation repeats:repeats]; + + //add to the runloop + [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode]; + + return timer; +} + +/*! + Returns a new NSTimer that, when added to a run loop, will fire after seconds. +*/ ++(CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)invocation repeats:(BOOL)repeats +{ + return [[self alloc] initWithFireDate:nil interval:seconds invocation:invocation repeats:repeats]; +} + +/*! + Returns a new NSTimer object and adds it to the current NSRunLoop object in the default mode. +*/ ++(CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats +{ + var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:target selector:aSelector userInfo:userInfo repeats:repeats] + + //add to the runloop + [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode]; + + return timer; +} + +/*! + Returns a new NSTimer that, when added to a run loop, will fire after seconds. +*/ ++(CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats +{ + return [[self alloc] initWithFireDate:nil interval:seconds target:target selector:aSelector userInfo:userInfo repeats:repeats]; +} + +/*! + Initializes a new NSTimer that, when added to a run loop, will fire at date and then, if repeats is YES, every seconds after that. +*/ +-(id)initWithFireDate:(CPDate)date interval:(CPTimeInterval)seconds invocation:(CPInvocation)invocation repeats:(BOOL)repeats +{ + self = [super init]; + + if (self) + { + _timeInterval = seconds; + _invocation = invocation; + _repeats = repeats; + _isValid = YES; + _fireDate = date; + } + + return self; +} + +/*! + Initializes a new NSTimer that, when added to a run loop, will fire at date and then, if repeats is YES, every seconds after that. +*/ +-(id)initWithFireDate:(CPDate)date interval:(CPTimeInterval)seconds target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats +{ + self = [super init]; + + if (self) + { + _timeInterval = seconds; + _selector = selector; + _target = target; + _repeats = repeats; + _isValid = YES; + _fireDate = date; + _userInfo = userInfo; + } + + return self; +} + +/*! + Returns the receiver’s time interval. +*/ +-(CPTimeInterval)timeInterval +{ + return _timeInterval; +} + +/*! + Returns the date at which the receiver will fire. +*/ +-(CPDate)fireDate +{ + return _fireDate; +} + +/*! + Resets the receiver to fire next at a given date. +*/ +-(void)setFireDate:(CPDate)date +{ + _fireDate = date; +} + +/*! + Causes the receiver’s message to be sent to its target. +*/ +-(void)fire +{ + if (_isValid) + { + //quick way to decide between invocation and target:selector: timer + if (_invocation != nil) + [_invocation invoke]; + else + [_target performSelector:_selector withObject:self]; + + //tell CPRunLoop to execute updates in the DOM + [[CPRunLoop currentRunLoop] performSelectors]; + + if (_repeats) + _fireDate = [CPDate dateWithTimeIntervalSinceNow:_timeInterval]; + } +} + +/*! + Returns a Boolean value that indicates whether the receiver is currently valid. +*/ +-(BOOL)isValid +{ + return _isValid; +} + +/*! + Stops the receiver from ever firing again and requests its removal from its NSRunLoop object. +*/ +-(void)invalidate +{ + _isValid = NO; + _userInfo = nil; + _invocation = nil; + _target = nil; + _selector = nil; +} + +/*! + Returns the receiver's userInfo object. +*/ +-(id)userInfo +{ + return _userInfo; +} + +@end \ No newline at end of file diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index 35e48c6..172d879 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -47,6 +47,7 @@ @import "CPRunLoop.j" @import "CPSortDescriptor.j" @import "CPString.j" +@import "CPTimer.j" @import "CPUndoManager.j" @import "CPURLConnection.j" @import "CPURLRequest.j" -- 1.6.0.2