Copyright © 2003, 2004 Dave Bayer. Subject to the terms and conditions of the MIT License.
#import <Foundation/Foundation.h>
@class PreferenceController;
@interface MenuNoteController : NSObject
{
NSStatusItem *statusItem;
IBOutlet NSMenu *theMenu;
PreferenceController *preferenceController;
NSTimer *mainTimer;
NSTimeInterval wakeDate, nextDate, wakeTime;
BOOL awake;
}
- (void) setTimer;
- (void) freeTimer;
- (void) fireTimer;
- (IBAction) openPrefs: (id) sender;
- (IBAction) openHelp: (id) sender;
@end
Copyright © 2003, 2004 Dave Bayer. Subject to the terms and conditions of the MIT License.
#include <math.h>
#include <Carbon/Carbon.h>
#import "MenuNoteController.h"
#import "PreferenceController.h"
@implementation MenuNoteController
+ (void) initialize
{
[PreferenceController registerDefaults];
[PreferenceController restoreDefaults];
}
- (void) displayWillSleep
{
NSLog(@"DisplayWillSleep");
NSLog(@"");
[self freeTimer];
wakeTime += [NSDate timeIntervalSinceReferenceDate] - wakeDate;
awake = NO;
}
- (void) displayDidWake
{
NSLog(@"DisplayDidWake");
[self setTimer];
}
static void notifyProc(void *userData, short message, void *notifyData)
{
MenuNoteController *self = userData;
if (message == kDMNotifyDisplayWillSleep)
[self displayWillSleep];
else if (message == kDMNotifyDisplayDidWake)
[self displayDidWake];
}
- (void) enableDisplayEvents
{
ProcessSerialNumber serial;
NSLog(@"enableDisplayEvents");
GetCurrentProcess(&serial);
DMRegisterExtendedNotifyProc(notifyProc, (void *) self, nil, &serial);
}
- (void) disableDisplayEvents
{
ProcessSerialNumber serial;
GetCurrentProcess(&serial);
DMRemoveExtendedNotifyProc(notifyProc, nil, &serial, nil);
}
- (void) setTimer
{
mainTimer = [NSTimer
scheduledTimerWithTimeInterval: 0.0
target: self
selector: @selector(timerAction:)
userInfo: nil
repeats: NO];
[mainTimer retain];
}
- (void) freeTimer
{
if (mainTimer != nil)
{
[mainTimer invalidate];
[mainTimer release];
}
mainTimer = nil;
}
- (void) fireTimer
{
[mainTimer fire];
}
- (void) resetTimer: (NSTimeInterval) fireDate
{
[self freeTimer];
mainTimer = [[NSTimer alloc]
initWithFireDate: [NSDate dateWithTimeIntervalSinceReferenceDate: fireDate]
interval: nil
target: self
selector: @selector(timerAction:)
userInfo: nil
repeats: NO];
[mainTimer retain];
[[NSRunLoop currentRunLoop] addTimer: mainTimer forMode: NSDefaultRunLoopMode];
}
- (void) setTitle: (NSTimeInterval) date
{
int wakeSeconds = wakeTime + date - wakeDate;
NSMutableString *format = [NSMutableString stringWithCapacity: 64];
[format setString: timeFormat];
[format replaceOccurrencesOfString: @"%T"
withString: [NSString stringWithFormat:@"%d", wakeSeconds/3600]
options: NSLiteralSearch range: NSMakeRange(0, [format length])];
[format replaceOccurrencesOfString: @"%U"
withString: [NSString stringWithFormat:@"%02d", (wakeSeconds/60)%60]
options: NSLiteralSearch range: NSMakeRange(0, [format length])];
[format replaceOccurrencesOfString: @"%V"
withString: [NSString stringWithFormat:@"%02d", wakeSeconds%60]
options: NSLiteralSearch range: NSMakeRange(0, [format length])];
NSCalendarDate *time = [[[NSDate dateWithTimeIntervalSinceReferenceDate: date]
dateWithCalendarFormat: format timeZone: nil]
dateByAddingYears: 0 months: 0 days: 0
hours: hourOffset
minutes: minuteOffset
seconds: 0];
NSString *title = [NSString stringWithFormat:@"%@", time];
if (stripZeros)
{
NSMutableString *strip = [NSMutableString stringWithCapacity: 64];
[strip setString: title];
[strip replaceOccurrencesOfString: @"0" withString: @"" options: NSLiteralSearch range: NSMakeRange(0, 1)];
[strip replaceOccurrencesOfString: @" 0" withString: @" " options: NSLiteralSearch range: NSMakeRange(0, [strip length])];
title = strip;
}
[statusItem setTitle: title];
}
- (void) timerAction: (NSTimer *) timer
{
NSTimeInterval fireDate, roundedDate, fracPart;
NSLog(@"timerAction");
fireDate = [NSDate timeIntervalSinceReferenceDate];
if (!awake)
{
wakeDate = fireDate;
awake = YES;
}
else if (fireDate > nextDate + 1.0)
{
wakeDate += fireDate - nextDate;
}
NSLog(@"wakeDate = %@", [[NSDate dateWithTimeIntervalSinceReferenceDate: wakeDate]
dateWithCalendarFormat: @"%H:%M:%S.%F" timeZone: nil]);
NSLog(@"wakeTime = %.2f", wakeTime + fireDate - wakeDate);
roundedDate = fireDate + roundTo/2;
roundedDate -= fmod(roundedDate, roundTo);
fireDate = roundedDate + roundTo;
fracPart = fmod(fireDate, refreshRate);
if (fracPart > 0) fireDate += refreshRate - fracPart;
nextDate = fireDate;
[self resetTimer: fireDate];
[self setTitle: roundedDate];
}
- (void) awakeFromNib
{
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSVariableStatusItemLength] retain];
[statusItem setMenu: theMenu];
[statusItem setEnabled: YES];
[self enableDisplayEvents];
[self setTimer];
wakeTime = 0.0;
awake = NO;
}
- (IBAction) openPrefs: (id) sender
{
if (!preferenceController)
{
preferenceController = [[PreferenceController alloc] init];
[preferenceController setController: self];
}
[[preferenceController window] makeKeyAndOrderFront: nil];
}
Bypass Apple Help, and instead open help using the user's preferred browser:
- (IBAction) openHelp: (id) sender
{
static NSString *help = @"Contents/Resources/source/index.html";
[[ NSWorkspace sharedWorkspace ] openFile:
[ NSString pathWithComponents:
[ NSArray arrayWithObjects:
[[ NSBundle mainBundle ] bundlePath ], help, nil ]]];
}
- (void) dealloc
{
NSLog(@"dealloc");
[self freeTimer];
[statusItem release];
[preferenceController release];
[super dealloc];
}
@end