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.