source: trunk/Cocoa/Pester/Source/PSTimer.m@ 63

Last change on this file since 63 was 61, checked in by Nicholas Riley, 21 years ago

Pester 1.1b1.

PSPowerManager: Fixed delegate method selectors to better reflect what
is going on (Apple's docs in IOKit Fundamentals help with this; the
kIOMessage*Sleep constants are really poorly named).

VERSION: Updated for 1.1b1.

PSSpeechAlert.h: Fixed company name.

PSAlert.[hm]: Added -prepareForAlarm: to support PSWakeAlert.

PSTimer.[hm]: Replacement for NSTimer that works properly across
sleep/wake cycles and will schedule wake timers.

PSAlerts.[hm]: Added -prepareForAlarm: to support PSWakeAlert.

Read Me.rtfd: Updated for 1.1b1.

PSAlarm.[hm]: Added -setWakeUp:, invoke -[PSAlerts prepareForAlarm],
replaced alarm timer NSTimer with PSTimer.

PSApplication.[hm]: Replaced dock update timer NSTimer with PSTimer.
Uncovered some issues, need to fix later. Enable alarm discard for
beta release.

PSWakeAlert.[hm]: Shared alert implementation for wakeup. Doesn't do
anything at trigger time, but uses new preparation interface to work
at alarm set time (should work for repeating alarms too, but I didn't
bother to test...)

PSAlarmSetController.m: Added support for PSWakeAlert. Save default
alert information on quit. Removed debug statements on hide/unhide;
it works fine regardless of whether the app is explicitly hidden or
the window hides itself.

PSAlarms.m: PSTimer support - invoke +[PSTimer setUp] to initialize
timer list.

File size: 6.6 KB
Line 
1//
2// PSTimer.m
3// Pester
4//
5// Created by Nicholas Riley on Sun Jan 05 2003.
6// Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "PSTimer.h"
10#import "PSAlarm.h"
11#import "PSPowerManager.h"
12
13NSTimer *PSTimerCurrent = nil;
14PSTimer *PSTimerOnWake = nil;
15NSMutableArray *PSTimerAllTimers = nil;
16
17@interface PSTimer (Private)
18+ (void)_schedule;
19@end
20
21@implementation PSTimer
22
23+ (void)setUp;
24{
25 static PSPowerManager *powerManager;
26
27 if (powerManager == nil) {
28 powerManager = [[PSPowerManager alloc] initWithDelegate: self];
29 PSTimerAllTimers = [[NSMutableArray alloc] init];
30 }
31}
32
33+ (void)_schedule;
34{
35 NSDate *aboutNow = [NSDate dateWithTimeIntervalSinceNow: 0.1];
36 [PSTimerCurrent invalidate]; [PSTimerCurrent release]; PSTimerCurrent = nil;
37 PSTimerOnWake = nil;
38 if ([PSTimerAllTimers count] > 0) {
39 PSTimer *timer = nil;
40 NSEnumerator *e;
41 [PSTimerAllTimers sortUsingSelector: @selector(compare:)];
42 // NSLog(@"_schedule: timers %@", [PSTimerAllTimers description]);
43 e = [PSTimerAllTimers objectEnumerator];
44 while ( (timer = [e nextObject]) != nil) {
45 if ([timer isWakeUp]) {
46 PSTimerOnWake = timer;
47 // NSLog(@"scheduling wake timer %@", timer);
48 break;
49 }
50 }
51 e = [PSTimerAllTimers objectEnumerator];
52 while ( (timer = [e nextObject]) != nil) {
53 if ([[timer fireDate] compare: aboutNow] != NSOrderedDescending) {
54 [timer performSelector: @selector(_timerExpired) withObject: nil afterDelay: 0];
55 return;
56 } else {
57 NSTimeInterval ti = [[timer fireDate] timeIntervalSinceNow];
58 if (ti > 0.1) {
59 PSTimerCurrent = [[NSTimer scheduledTimerWithTimeInterval: ti target: timer selector: @selector(_timerExpired) userInfo: nil repeats: NO] retain];
60 // NSLog(@"setting timer: %@", PSTimerCurrent);
61 } else {
62 // NSLog(@"timer would have been too fast, setting: %@", timer);
63 [timer performSelector: @selector(_timerExpired) withObject: nil afterDelay: 0];
64 }
65 return;
66 }
67 }
68 NSAssert(NO, @"shouldn’t get here");
69 } else {
70 // NSLog(@"_schedule: no timers");
71 }
72}
73
74+ (void)_timerAdded:(PSTimer *)timer;
75{
76 NSAssert1([PSTimerAllTimers indexOfObject: timer] == NSNotFound, @"PSTimerAllTimers already contains %@", timer);
77 [PSTimerAllTimers addObject: timer];
78 [self _schedule];
79}
80
81+ (void)_timerDeleted:(PSTimer *)timer;
82{
83 NSAssert1([PSTimerAllTimers indexOfObject: timer] != NSNotFound, @"PSTimerAllTimers does not contain %@", timer);
84 [PSTimerAllTimers removeObject: timer];
85 [self _schedule];
86}
87
88#pragma mark private
89
90- (void)_setFireDate:(NSDate *)date;
91{
92 if (fireDate != date) {
93 [fireDate release];
94 fireDate = [date retain];
95 if (fireDate != nil) {
96 isValid = YES;
97 }
98 }
99}
100
101- (void)_setFireDateFromInterval;
102{
103 [self _setFireDate: [NSDate dateWithTimeIntervalSinceNow: timeInterval]];
104}
105
106- (void)_invalidate;
107{
108 isValid = NO;
109 [[self class] _timerDeleted: self];
110}
111
112- (void)_timerExpired;
113{
114 if (!isValid) return; // in case the timer went off after we were invalidated
115 [self retain]; // make sure we’re still accessible during the invocation
116 // NSLog(@"timer expired: %@", self);
117 if (repeats) {
118 [invocation invoke];
119 if (isValid) {
120 [self _setFireDateFromInterval];
121 [[self class] _schedule];
122 // NSLog(@"timer repeats: %@", self);
123 }
124 } else {
125 [self _invalidate];
126 [invocation invoke];
127 }
128 [self release];
129}
130
131#pragma mark initialize-release
132
133- (id)initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)anObject repeats:(BOOL)yesOrNo;
134{
135 if ( (self = [self init]) != nil) {
136 invocation = [[NSInvocation invocationWithMethodSignature:
137 [aTarget methodSignatureForSelector: aSelector]] retain];
138 [invocation setSelector: aSelector];
139 [invocation setTarget: aTarget];
140 [invocation setArgument: &self atIndex: 2];
141 userInfo = [anObject retain];
142 repeats = yesOrNo;
143 timeInterval = ti;
144 [invocation retainArguments]; // mimics retain behavior
145 [self _setFireDateFromInterval];
146 [[self class] _timerAdded: self]; // mimics runloop retention behavior
147 }
148 return self;
149}
150
151+ (PSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)anObject repeats:(BOOL)yesOrNo;
152{
153 PSTimer *timer = [[self alloc] initWithTimeInterval: ti target: aTarget selector: aSelector userInfo: anObject repeats: yesOrNo];
154 [timer release];
155 return timer;
156}
157
158- (void)dealloc;
159{
160 // NSLog(@"DEALLOC %@", self);
161 isValid = NO;
162 [fireDate release]; fireDate = nil;
163 [invocation release]; invocation = nil;
164 [userInfo release]; userInfo = nil;
165 [super dealloc];
166}
167
168#pragma mark accessing
169
170- (NSDate *)fireDate;
171{
172 return fireDate;
173}
174
175- (void)invalidate;
176{
177 repeats = NO;
178 [self _invalidate];
179}
180
181- (BOOL)isValid;
182{
183 return isValid;
184}
185
186- (id)userInfo;
187{
188 return userInfo;
189}
190
191- (BOOL)isWakeUp;
192{
193 return isWakeUp;
194}
195
196- (void)setWakeUp:(BOOL)doWake;
197{
198 isWakeUp = doWake;
199}
200
201- (NSComparisonResult)compare:(PSTimer *)other;
202{
203 return [fireDate compare: [other fireDate]];
204}
205
206- (NSString *)description;
207{
208 return [NSString stringWithFormat: @"%@: at %@ do %@ on %@", [super description], [self fireDate], NSStringFromSelector([invocation selector]), [[invocation target] class]];
209}
210
211@end
212
213@implementation PSTimer (PSPowerManagerDelegate)
214
215+ (BOOL)powerManagerShouldIdleSleep:(PSPowerManager *)powerManager;
216{
217 [PSTimerCurrent invalidate];
218 if (PSTimerOnWake != nil) {
219 NSDate *date = [PSTimerOnWake fireDate];
220 NSLog(@"%lf sec remain until alarm", [date timeIntervalSinceNow]);
221 if ([date timeIntervalSinceNow] > 30) {
222 NSLog(@"going to sleep, setting timer %@", PSTimerOnWake);
223 [PSPowerManager setWakeTime: [[PSTimerOnWake fireDate] addTimeInterval: -15]];
224 return YES;
225 } else {
226 NSLog(@"not setting timer, will attempt to prevent idle sleep");
227 return NO;
228 }
229 }
230 return YES;
231}
232
233+ (void)powerManagerWillDemandSleep:(PSPowerManager *)powerManager;
234{
235 [self powerManagerShouldIdleSleep: powerManager];
236 return;
237}
238
239+ (void)powerManagerDidWake:(PSPowerManager *)powerManager;
240{
241 if (PSTimerCurrent != nil) {
242 [self _schedule];
243 }
244}
245
246@end
Note: See TracBrowser for help on using the repository browser.