This is Cassandra.m in view mode; [Download] [Up]
//
// Cassandra.m
// Copyright (c) 1988, 1989, 1990, 1991, 1992 by Jiro Nakamura
// All rights reserved
//
// Main control object of Cassandra. Routes most calls to their proper places
// and handles alarm control.
//
// by Jiro Nakamura (jiro@shaman.com)
//
// RCS Information
// Revision Number-> $Revision: 2.19 $
// Last Revised-> $Date: 92/11/10 00:50:10 $
//
static char authorid[] = "$Author: jiro $";
static char rcsid[] = "$Id: Cassandra.m,v 2.19 92/11/10 00:50:10 jiro Exp Locker: jiro $";
static char copyrightid[] =
"Copyright (C) 1988, 1989, 1990, 1991 by Jiro Nakamura. "
"All Rights Reserved.";
#import <stdio.h>
#import <libc.h>
#import <time.h>
#import <sys/file.h>
#import <strings.h>
#import <appkit/Form.h>
#import <appkit/Button.h>
#import <appkit/Panel.h> /* for NXRunAlertPanel() */
#import <appkit/publicWraps.h> /* for NXBeep( ) */
#import <appkit/Application.h> /* for NX_MODALRESPTHRESHOLD */
#import <appkit/PageLayout.h>
#import <dpsclient/wraps.h>
#import <soundkit/Sound.h>
#import <bsd/dev/m68k/evsio.h> /* For screen handling */
#import "Cassandra.h"
#import "Event.h"
#import "Global.h"
#import "misc.h"
#import "calendar.h"
#import "EventLog.h"
#import "Notepad.h"
#import "Overview.h"
#import "Today.h"
#define WHENREADY -1.0 // for startAlarmTimedEntry
#define NOW 0.0
#define MAXSECONDS (24 * 60 * 60) // 24 hours in seconds
char *getlogin(); // This isn't defined anywhere....
// NeXT, get on your feet!
@implementation Cassandra
// We override new in order to set the delegate of the application object
// to itself. This allows the appDidInit: and appDidHide: delegate methods
// to be invoked properly.
/* This is only needed because things are setup wierd in the nib
* file, as near as I can tell... Garance/Dec 22/95
*/
+ new
{
#ifdef DEBUG
fprintf(stderr,"Cassandra being created.\n");
#endif
self = [super new];
[self setDelegate:self];
return self;
}
/* The main reason for the following methods are just to avoid warnings
* about rcsid, etc, being unreferenced... Garance/Jul 28/94
*/
- (const char *) returnRcsid
{
return rcsid;
}
- (const char *) returnAuthorid
{
return authorid;
}
- (const char *) returnCopyrightid
{
return copyrightid;
}
// appDidInit is called as the first thing in the run loop of the
// application. At this point, everything is created, but we haven't entered
// the event loop yet. appDidInit first loads the global variables in
// from the defaults database, then appDidInit creates a new instance
// Clock, and
// makes it a subview of the application icon window (obtained through
// the appIcon method of Application). It then goes about and sets the
// lockFile for cassandra, opening the windows we need, etc.
- appDidInit: app
{
FILE *lFile; // lockFile file descriptor
char line1[127], tmpFile[129];
char tmp[256];
NXRect cvFrame; // contentView frame
id applicationIcon = [NXApp appIcon]; // Our beloved icon
#ifdef DEBUG
fprintf(stderr,"Cassandra did initialize."
" (From Cassandra.m)\n");
#endif
alarmFree = TRUE;
snooze = 0;
secondsUntilEvent = 0.0;
queueModified = TRUE;
now = *timeNow(); // Set the time
[global load:self]; // Let's load the global variables
queueModified = YES; // Make sure queue gets re-read
// Check for lockfile, if none, create one. If one, ask user
// what he/she wants to do.
strcpy(lockFile,[global eventFile]); // "eventFile" + ".lck"
strcat(lockFile,".lck");
if( access( lockFile, F_OK ) == 0) // if it exists
{
lFile = fopen(lockFile,"r");
fgets(line1,128,lFile);
fclose(lFile);
if( NXRunAlertPanel("Event File in Use",line1,
"Quit","Open Anyway",NULL) == 1)
exit(1);
}
// Ok. None exists. Create the lockFile giving the current
// username and time.
lFile = fopen( lockFile, "w");
fprintf(lFile, "The Event file is still in use. "
"It was opened by %s on %s.\n"
"Do you want to open it anyway?",
NXUserName(),
ascMyTime( (struct tm *)timeNow(),
[global showSeconds],
[global militaryTime]));
fclose(lFile);
// Check to see if there is a compressed EventFile
strcpy( tmpFile, [global eventFile]);
strcat( tmpFile, ".Z");
if( access([global eventFile], R_OK) != 0 &&
access( tmpFile, R_OK) == 0) // It exists
{
sprintf( tmp, "/usr/ucb/uncompress %s", tmpFile);
#ifdef DEBUG
fprintf(stderr, "%s: now doing system(\"%s\")",
PROGNAME, tmp);
#endif
system( tmp);
}
// Set up the clock icon
// This is from ClockApp (used w/ author's permission)
[[applicationIcon contentView] getFrame:&cvFrame];
NXInsetRect(&cvFrame, 3.0, 3.0); //let 's not touch the border
clockView = [Clock newFrame:&cvFrame];
[[applicationIcon contentView] addSubview:clockView];
[self defaultsDidChange:self];
[applicationIcon display];
// then, set the target and action of Clock so we can use it.
[clockView setTarget: self];
[clockView setAction: @selector(tick:)];
[self updateClockViewMessage: self];
// If we should source .cassandra/login at login-time
if( [global sourceLoginOnLaunch] && [global autoLaunched])
{
sprintf(tmp, "/bin/sh %s",[global sourceLoginFile] );
#ifdef DEBUG
fprintf(stderr, "%s: now doing system(\"%s\")",
PROGNAME, tmp);
#endif
system( tmp );
}
// If we are opening the Overview at launch
if( [global overviewOnLaunch])
[overview open: self];
// If we are opening the Log at launch
if( [global eventLogOnLaunch])
[eventLog open:self];
// If we are opening the Notepad at launch
if( [global notepadOnLaunch])
[notepad open:self];
// If we are opening Today at launch
if( [global todayOnLaunch])
[today open:self];
// If we are opening Week at launch
if( [global weekOnLaunch])
[week open:self];
[self startAlarmTimedEntry: NOW];
// If we should hide ourselves at launch...
if( [global hideOnLaunch] && [global autoLaunched] )
[NXApp perform: @selector(hide:)
with: self
afterDelay: 1
cancelPrevious: NO];
return self;
}
//
// appDidHide is called if the user hides the application.
// appDidUnhide is called when the user unhides the application.
// These aren't implemented (just yet).
//
- appDidHide
{
return self;
}
- appDidUnhide
{
[overview timeUpdate:self];
[today timeUpdate: self];
[week timeUpdate: self];
if( timeNow()->tm_mday != now.tm_mday)
{
[today update];
[overview monthUpdate: self];
now = *timeNow();
}
return self;
}
//
// Cassandra is about to quit. First, remove the lockfile,
// the close all the windows (they will save their positions
// automatically) and then quit.
//
- cassandraWillQuit:sender;
{
char tmp[256];
unlink( lockFile); // Remove lockFile before quiting
if( [global compressEvents])
{
sprintf( tmp, "/usr/ucb/compress -f %s&", [global eventFile]);
#ifdef DEBUG
fprintf(stderr,"Compressing event file...\n");
fprintf(stderr, "%s: now doing system(\"%s\")",
PROGNAME, tmp);
#endif
system( tmp);
}
// If we should source .cassandra/logout at logout-time
if( [global sourceLoginOnLaunch] && [global autoLaunched] )
{
sprintf(tmp, "/bin/sh %s",[global sourceLogoutFile] );
#ifdef DEBUG
fprintf(stderr, "%s: now doing system(\"%s\")",
PROGNAME, tmp);
#endif
system( tmp );
}
if( [overview isVisible])
[overview performClose:self];
if( [global isVisible])
[global performClose:self];
if( [notepad isVisible])
[notepad performClose:self];
if( [eventLog isVisible])
[eventLog performClose:self];
if( [today isVisible])
[today performClose: self];
if( [week isVisible])
[week performClose: self];
if( [addEventPanel isVisible])
[addEventPanel performClose: self];
if( [editEventPanel isVisible])
[editEventPanel performClose: self];
return self;
}
//
// We want to catch the powerOff and logOut messages from the WM
// The user should manually quit Cassandra or else window
// positions will NOT be saved.
//
- appPowerOffIn: (int) ms andSave: (int) aFlag
{
// We are powering off, oh no....
if( aFlag == YES) // If we are allowed to save, then
[self cassandraWillQuit: self];
else
unlink( lockFile); // At least remove the lockFile
// before quiting
return self;
}
//
// Brings up the information panel.
//
- info:sender
{
if (!infoPanel)
{
infoPanel=[self loadNibSection:"InfoPanel.nib" owner:self withNames:NO];
}
[infoPanel orderFront:self];
return self;
}
//
// Brings up the help panel.
//
- help:sender
{
if (!helpPanel)
{
helpPanel = [self loadNibSection:"HelpPanel.nib" owner:self withNames:NO];
}
[helpPanel orderFront:self];
return self;
}
//
// Brings up the new Preferences panel.
//
- showPrefsPanel:sender;
{
if (!PrefsPanel)
{
PrefsPanel = [self loadNibSection:"PrefsPanel.nib"
owner:self withNames:NO];
}
[PrefsPanel makeKeyAndOrderFront:self];
return self;
}
//
// Brings up the Calculator window.
//
- calculator:sender
{
if( calculatorWindow == nil)
{
calculatorWindow = [self loadNibSection: "Calculator.nib"
owner:self withNames:NO];
}
[calculatorWindow makeKeyAndOrderFront:self];
return self;
}
// quit is called by the quit button on the main menu.
// checks to see if the user really wants to quit, then invokes
// the terminate method of itself if she or he does.
- quit: sender
{
#ifdef ASK_IF_QUITTING
if( NXRunAlertPanel(NULL,"Really quit?",
"Quit","Cancel",NULL) == 1)
{
[self cassandraWillQuit:self];
[NXApp terminate: self];
}
#else
[self cassandraWillQuit:self];
[NXApp terminate: self];
#endif
return nil;
}
// closeKeyWindow: is called by the Close button on the Window submenu
// it closes the key window (naturally).
- closeKeyWindow:sender
{
[[self keyWindow] performClose:self];
return self;
}
// saveKeyWindow: is called by the Save button on the Window submenu
// it saves the key window (naturally).
- saveKeyWindow:sender
{
if( [[self keyWindow] respondsTo: @selector(save)])
[[self keyWindow] save];
return self;
}
// miniaturizeKeyWindow: is called by the Minituarize button on the
// Window submenu, it miniaturizes the key window (naturally).
- miniaturizeKeyWindow:sender
{
[[self keyWindow] performMiniaturize:self];
return self;
}
// Runs the page layout panel
- runPageLayout: sender
{
[[PageLayout new] runModal];
return self;
}
- print: sender
{
id mainWin = [NXApp keyWindow];
if( mainWin == nil )
NXBeep();
return [mainWin printPSCode: sender];
}
// =======================================================
// Alarm Routines
//========================================================
// Ideally, these should be in a separate class.
// But efficiency dictates this method.
// They check the queue to see when the next event is, plant
// a timer entry for that time, then when it calls, bring
// up the alarm panel, play the jingle, etc., handle the
// anniversary events/snooze events/etc.
- alarmStart:sender
{
Event *ev;
#ifdef DEBUG
fprintf(stderr,"Alarm starting\n");
#endif
// Wake up an alarm is starting
[NXApp activateSelf: NO]; // Let's activate ourself!
[Sound getVolume: &oldVolumeLeft:&oldVolumeRight];
ev = [Event newAt:[global eventFile]];
[ev firstEvent]; // Read the first event
if( [alarmPanel isVisible]) // If it is visible
{ // then let us just
if( [ev playAlarm] && alarmFree && ![ev runCommand])
// play the alarm sound
[self playAlarm: [ev alarmSound]];
[[self stopAlarmTimedEntry] startAlarmTimedEntry: 3*60.0];
[ev free];
return self; // repeat after three minutes
}
if( [ev showMessage])
{
[alarmPanelTime setStringValue:
ascMyTime([ev time], NOSEC,
[global militaryTime]) at:0];
[alarmPanelMessage setStringValue : [ev message] at:0];
[alarmPanelNextEvent setStringValue: ascMyTime(
fixAnniversary([ev time], [ev anniversary],
[ev annvSpecial]),
NOSEC, [global militaryTime]) at: 0];
if( [ev snoozeNo] > 1)
[snoozeButton setEnabled : TRUE];
else
[snoozeButton setEnabled : FALSE];
[snoozeButton setState: 0];
[okButton setState: 0];
[alarmPanel makeKeyAndOrderFront: self];
NXPing();
}
#ifdef DEBUG
fprintf(stderr, "Starting alarm with: %s\n : %s",
ascMyTime([ev time], NOSEC, [global militaryTime]),
[ev message]);
#endif
if( alarmFree && [ev playAlarm] && ![ev runCommand] )
[self playAlarm: [ev alarmSound]];
else
{
#ifdef DEBUG
fprintf(stderr,"Alarm is not free or no alarm.....\n");
#endif
if( [ev runCommand] )
system( [ev alarmSound] );
}
[ev free];
[self nextSnoozeAlarm];
return self;
}
- playAlarm: (const char *) alarmSound
{
int error;
// From 1.0 Docs, Sound Kit, pp22-498
[Sound getVolume: &oldVolumeLeft:&oldVolumeRight];
#ifdef DEBUG
fprintf(stderr,"Old volume L=%f R=%f, New Volume =%f\n",
oldVolumeLeft, oldVolumeRight, [global volume]);
#endif
alarmFree = FALSE;
// if( index(alarmSound, '/') == (char *) 0)
soundfile = [Sound findSoundFor: alarmSound];
// else
// soundfile = [Sound newFromSoundfile: alarmSound];
if( soundfile != nil)
{
[soundfile setDelegate: self];
if( [global volume] >= 0)
[Sound setVolume: [global volume]:
[global volume]];
error = [soundfile play];
if( error != 0)
{
fprintf(stderr,"Cassandra: "
"There was an error %d (%s)"
" playing the alarm sound: %s.\n",
error, SNDSoundError(error),
alarmSound);
alarmFree = TRUE;
// Restore old volume
[Sound setVolume: oldVolumeLeft :
oldVolumeRight];
}
}
else
{
fprintf(stderr,
"%s: Couldn't find the alarm sound <%s>."
"Substituting with obnoxious system beep.\n",
PROGNAME, alarmSound);
NXBeep();
alarmFree = TRUE;
}
return self;
}
- hadError : sender
{
char errorString[200];
int error = [[sender soundBeingProcessed] processingError];
sprintf(errorString,
"Error #%d (%s) occured while playing the alarm sound <%s>.\n",
error, SNDSoundError(error),
[[sender soundBeingProcessed] name]);
NXRunAlertPanel("Alarm Error",errorString,
"Oh well...",NULL,NULL);
[self nextSnoozeAlarm];
[self queueDidChange: self];
// Restore old volume
[Sound setVolume: oldVolumeLeft: oldVolumeRight];
alarmFree = TRUE;
[soundfile free];
return self;
}
- didPlay: sender
{
#ifdef DEBUG
fprintf(stderr,"Alarm Freed! Restoring volume to %f and %f\n",
oldVolumeLeft, oldVolumeRight);
#endif
// If the alarm panel is invisible, it must mean the user
// meant for this to be a one shot deal, thus alert
// Cassandra that the queue changed so that it can update
// the alarm timers and overview window
if( ![alarmPanel isVisible])
[self queueDidChange: self];
[snoozeButton setEnabled : FALSE];
alarmFree = TRUE;
[soundfile free];
// Restore old volume
[Sound setVolume: oldVolumeLeft: oldVolumeRight];
return self;
}
- nextSnoozeAlarm
{
EFileLink here;
Event *ev;
ev = [Event newAt:[global eventFile]];
[ev firstEvent]; /* Read the first event */
here = [ev present];
snooze = 0; /* Initialize it to a good number, ie. nothing */
if( [ev snoozeNo] > 0)
{
struct tm next;
#ifdef DEBUG
fprintf(stderr,"Snooze %d times with "
"intervals of %d minutes.\n\n",
[ev snoozeNo], [ev snoozeInt]);
#endif
/* Decrease the number of snooze events by 1 */
[ev setSnoozeNo : ([ev snoozeNo] -1)];
/* Add the snooze interval to minutes */
/* Don't worry about overflow */
/* insertEvent can handle that */
next = *[ev time];
next.tm_min += [ev snoozeInt];
/* Set event parameters so that the inserted one gets nixed */
/* properly when its time is due */
[ev setDestroy :1];
[ev setAnniversary :0];
[ev setPriority :1];
[ev setTime: &next];
/* Set the snooze marker so we know which event to nix later */
/* and insert the new event */
snooze = [ev insertEvent];
// Turn the queueModified flag on so that the next
// timerUpdate will re-read the queue for the first event
queueModified = TRUE;
[ev free];
}
[self alarmReset: self];
return self;
}
- alarmSnooze : sender
{
#ifdef DEBUG
fprintf(stderr,"Alarm snoozeing....\n");
#endif
if( [alarmPanel isVisible])
{
if( !alarmFree)
{
[soundfile stop];
[soundfile free];
alarmFree = TRUE;
}
[alarmPanel close];
[self queueDidChange: self];
// Restore old volume
[Sound setVolume: oldVolumeLeft: oldVolumeRight];
}
return self;
}
- alarmStop: sender
{
if( [alarmPanel isVisible])
{
#ifdef DEBUG
fprintf(stderr,"Alarm stopping.\n");
fprintf(stderr,"Restoring volume to %f and %f\n",
oldVolumeLeft, oldVolumeRight);
#endif
if( !alarmFree)
{
[soundfile stop];
[soundfile free];
alarmFree = TRUE;
}
[alarmPanel close];
// Restore old volume
[Sound setVolume: oldVolumeLeft: oldVolumeRight];
if( snooze > 0 )
{
id ev;
ev = [Event newAt:[global eventFile]];
[ev deleteEvent: snooze];
[ev free];
snooze = 0;
}
[self queueDidChange: self];
}
return self;
}
// This is connected to the Reset/Cancel Button on the main menu->
// Modify Events submenu.
- resetCancel : sender
{
Event *ev;
ev = [Event newAt:[global eventFile]];
[ev firstEvent]; /* Read the first event */
if( [ev present] == 0)
{
NXRunAlertPanel("Alert",
"You cannot reset/cancel the next event "
"since there are no events...",
"OK", NULL, NULL);
[ev free];
return self;
}
if( NXRunAlertPanel( "Alert",
"This will reset the next event. "
"Are you sure you want to do this?",
"Do it","Cancel",NULL) == 1)
{
[self alarmReset:self];
[self queueDidChange: self];
}
[ev free];
return self;
}
// Actually reset the next event.
// Delete the first event in the queue. Log it if it has a high
// enough priority. Check if it is an anniversary event, and handle
// that.
- alarmReset: sender
{
Event *ev;
FILE *fd;
int temp;
static struct tm lastEventTime;
ev = [Event newAt:[global eventFile]];
[ev firstEvent]; /* Read the first event */
if( [ev priority] >= [global lowPriority] && [ev present] != 0)
{
char errormsg[128];
// Ok, we are writing to the event log, just to be sure,
// let's tell the event log object to save itself.
[eventLog save];
sprintf(errormsg, "Fatal error while creating "
"the log file %s", [global eventLogFile]);
// Check to make sure it exists, if it does not
// we have to create it and stick a header on it
if( access( [global eventLogFile], F_OK ) == -1)
{
if( ( fd = fileOpen( (char *)[global eventLogFile],
"a", errormsg)) != NULL)
{
fprintf(fd, "{\\rtf0\\ansi"
"{\\fonttbl\\f0\\fswiss "
"Helvetica;}\n}\n");
fclose( fd);
}
else
fprintf(stderr,"%s: Couldn't create logfile\n",
PROGNAME);
}
sprintf(errormsg, "Fatal error while appending to "
"the log file %s", [global eventLogFile]);
if( ( fd = fileOpen((char *) [global eventLogFile],"a",
errormsg)) != NULL)
{
fseek(fd, -2, SEEK_END); // Remove bracket from end
if( lastEventTime.tm_mday != timeNow()->tm_mday ||
lastEventTime.tm_mon != timeNow()->tm_mon ||
lastEventTime.tm_year != timeNow()->tm_year)
{
fprintf(fd, "\\par\\f0\\b %s\\par\n",
ascMyDate([ev time]));
lastEventTime = *timeNow();
}
if( [ev priority] > [global highPriority])
fprintf(fd, "\\f0\\b ");
else
fprintf(fd, "\\f0\\b0 ");
if( [global militaryTime])
fprintf(fd, "\t%2d:%02d\t%s"
"\\par\n",
[ev hour], [ev min],
[ev message]);
else
{
temp = [ev hour];
if( temp > 12 )
temp -= 12;
if( temp == 0 )
temp = 12;
fprintf(fd, "\t%2d:%02d %s\t%s"
"\\par\n",
temp,
[ev min],
([ev hour]>11)?"pm":"am",
[ev message]);
}
fprintf(fd, "}");
fclose(fd);
[eventLog update];
}
else
fprintf(stderr,"couldn't open file\n");
}
else
{
#ifdef DEBUG
fprintf(stderr,"Not high enough priority to log.\n");
#endif
}
[ev murderEvent: [ev present]]; // Kill/delete/anniverserate event
// Turn the queueModified flag on so that the next timerUpdate
// will re-read the queue for the first event
[self queueDidChange: self];
[ev free];
return self;
}
// Message queueDidChange:sender
// Received if the event queue has changed in any fashion.
// Tells other objects to update themselves to respond to this change.
- queueDidChange: sender
{
// Notify the overview window object that the queue has changed
[overview queueDidChange:self];
// Notify the Today window to update itself just in case
[today update];
// Notify the Week window to update itself just in case
[week update];
// Update the clockView if necessary
[self updateClockViewMessage: self];
// Turn the queueModified flag on so that the next timerUpdate
// will re-read the queue for the first event
queueModified = TRUE;
// Check the next alarm, now that the flag has been set.
[self timerUpdate:self];
// And reschedule the timer entry for the next alarm.
// Give the user ten seconds to react
[[self stopAlarmTimedEntry] startAlarmTimedEntry: 10.0];
return self;
}
- updateClockViewMessage: sender
{
static char buf1[80], buf2[80];
extern const char *shortMonths[12];
//Check to see if we are using the snazzy digital clock, if we are
// then we want to snarf off the first event and pipe it to Clock
if( [global clockType] == CLOCK_DIGITAL)
{
Event *ev;
int hour;
char *suffix;
ev = [Event newAt:[global eventFile]];
[ev firstEvent]; // Read in the first event
hour = [ev hour];
if( ![global militaryTime])
{
if( hour >= 12 )
{
suffix = "p";
hour -= 12;
}
else
suffix = "a";
if( hour == 0 )
hour = 12;
}
else
suffix = "";
sprintf(buf1,"%2d:%02d%s %s %d", hour, [ev min], suffix,
shortMonths[ [ev mon] ], [ev mday]);
strncpy(buf2, [ev message], 20);
[clockView setMessage: buf1: buf2];
[ev free];
}
return self;
}
- defaultsDidChange: sender
{
const char *str;
#ifdef DEBUG
fprintf(stderr,
"Defaults did change... App compensating.\n");
#endif
[overview defaultsDidChange: self];
[today defaultsDidChange: self];
[week defaultsDidChange: self];
// Read the ShowSeconds default and process it.
[clockView setShowSecondsToBool: [global showSeconds]];
[clockView setShowDateToBool: [global showDate]];
[clockView setClockTypeToInt: [global clockType]];
[clockView setMilitaryTimeToBool: [global militaryTime]];
[self updateClockViewMessage: self];
// Read the FaceBitmap default and process that.
str = [global clockfaceBitmapName];
[clockView setClockFaceToBitmapNamed:(str && str[0] ? str : NULL)];
return self;
}
// Message timerUpdate: sender
// This checks the present alarm and the first event of the queue and compares
// them. If the event at the very front is equal to or greater
// than the present time, then send off messages turning on the alarm system.
- timerUpdate :sender
{
static struct tm nextAlarmTime;
static int presentEventNumber;
static BOOL backlog = NO;
// Check to see if the queue has been modified/changed since the last
// time we read. If it has, we have to re-read the first event in
// since its time may have changed.
if( queueModified)
{
Event *ev;
ev = [Event newAt:[global eventFile]];
#ifdef DEBUG
fprintf(stderr,"Queue modified/new. "
"Re-reading event.\n");
#endif
[ev firstEvent]; // Read in the first event
/* Remember its number (place) in the queue */
presentEventNumber = [ev present];
/* and copy down the time at which it will occur */
nextAlarmTime = *[ev time];
queueModified = FALSE; // Reset the flag,
[ev free]; // and tidy up
}
else
{
// If the list was not modified, we can stick with the
// information we
// already have in presentEventNumber and nextAlarmTime
#ifdef DEBUG
fprintf(stderr,
"Queue not modified. Skipping re-read.\n");
#endif
}
/* How many more seconds until the event? */
if( presentEventNumber > 0) // Check if we're on the first event
secondsUntilEvent = secondsBetween( (struct tm *)
timeNow(), &nextAlarmTime );
else
secondsUntilEvent = 60*60*4; // Four hours
#ifdef DEBUG
fprintf(stderr, "Time now = %s.\n",
ascMyTime((struct tm*) timeNow(),
SEC, [global militaryTime]));
fprintf(stderr, "Event #%d's time = %s. \n"
"secondsUntilEvent = %6.1f sec. (%6.1f min.)\n",
presentEventNumber,
ascMyTime( &nextAlarmTime,SEC, [global militaryTime]),
secondsUntilEvent, secondsUntilEvent/60);
#endif
/* If it looks like the user has backlogged a lot of events, ask */
/* her or him if she or he wants to clear all of the until today */
if(secondsUntilEvent < (double) -(24*60*60) && presentEventNumber >0)
{
[NXApp unhide: self];
if(backlog == YES || NXRunAlertPanel("Backlog Warning",
"You have backlogged more than a day's "
"worth of events. "
"Would you rather clear all of them?",
"Yes","No",NULL) == 1)
{
Event *ev;
ev = [Event newAt:[global eventFile]];
backlog = YES;
do
{
[self alarmReset:self];
[ev firstEvent];
}
while( secondsBetween((struct tm *) timeNow(),
[ev time]) < 0 && [ev present] > 0);
[ev free];
[self queueDidChange:self];
return self;
}
else
backlog = NO;
}
/* If the event's time has come and it isn't a bogus event */
/* (0 or below are ignored) then start the alarm */
if( secondsUntilEvent <= 0 && presentEventNumber > 0)
{
[self alarmStart:self];
}
else
{
// OK, then let us start the bloody timer again
[self startAlarmTimedEntry: secondsUntilEvent];
}
return self;
}
// ===================================
// Timer Routines
// ===================================
// These handle the timer object
// for alarm control.
// Borrowed mostly off the Animator object.
void checkAlarm(teNum, now, cassandra)
DPSTimedEntry teNum;
double now;
id cassandra;
{
[cassandra stopAlarmTimedEntry];
[cassandra timerUpdate:cassandra];
}
- startAlarmTimedEntry:(double) fireWhen
{
double fireIn;
if( fireWhen > 0.0)
fireIn = fireWhen;
else
{
if (fireWhen = NOW || fireWhen < 0.0)
fireIn = 0.0; // Fire as soon as possible!
else
{
fireIn = secondsUntilEvent;
if( fireIn > MAXSECONDS )
fireIn = (double) MAXSECONDS;
}
}
#ifdef DEBUG
fprintf(stderr,"Starting alarmTE in %5.2f seconds. "
"(%d min. %d sec.)\n", fireIn,
((int) fireIn / 60), ((int)fireIn % 60));
#endif
alarmTE = DPSAddTimedEntry(fireIn, &checkAlarm,
self, NX_MODALRESPTHRESHOLD);
return self;
}
- stopAlarmTimedEntry
{
#ifdef DEBUG
fprintf(stderr,"Stopping alarmTE.\n");
#endif
if( alarmTE != NULL)
DPSRemoveTimedEntry (alarmTE);
alarmTE = NULL;
return self;
}
- tick:sender;
{
static minuteNow;
[overview timeUpdate:self];
[today timeUpdate: self];
// Check things that only needed to be checked periodically.
if( minuteNow != timeNow()->tm_min)
{
if( timeNow()->tm_mday != now.tm_mday)
{
[today update];
[overview monthUpdate: self];
[week update];
now = *timeNow();
}
}
return self;
}
- global { return global; }
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.