home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / CornerClock 1.9 / CornerClock.p < prev    next >
Encoding:
Text File  |  1997-06-23  |  18.3 KB  |  783 lines  |  [TEXT/CWIE]

  1. CornerClock is a pascal program based upon Masafumi Ueda's MBarClock program.
  2.  
  3. MBarClock was a program which displayed the time or date in the menu bar to the left
  4. of the Apple menu.  CornerClock uses that same feature and adds some other features.  
  5.  
  6. I converted Masafumi's MBarClock from C to Pascal, and then began forging it into 
  7. a chime replacement program.  Currently, if you have long chimes activated with your
  8. clock which comes with system 7.5, you may experience a very annoying distorted
  9. sound which interrupts your chime.  This is a known bug with the system, as it does not
  10. appear to lock the sound handle when it plays it (it should lock it because it plays it
  11. asynchronously).  CornerClock plays the hourly chime asynchronously, but locks the
  12. handle so you get a smooth play.
  13.  
  14. CornerClock will play a grandfather clock chime on the hour (3 chimes as 3:00, 4 at 4:00, etc.).
  15.  
  16. When you place the cursor over the time, it will change to the date for 2 seconds, then change back
  17. to the time (same feature in MBarClock except now there is sound).  I've also added some menus
  18. to CornerClock so that you can toggle the date and time, and force a chime.
  19.  
  20. There are many enhancements which can be made, like changing the chime sound, changing the
  21. volume, etc., but I'm releasing it as is to provide the Pascal community with some more sample 
  22. Pascal code.  Feel free to send me any questions or notes of thanks.
  23.  
  24. 2/4/96:  v1.1 - Fixed bug so that 12:00 noon displays as 12:00 instead of 0:00.
  25. 2/10/96: v1.2 - Added a toggle under the File menu for disabling the chime.
  26. 2/29/96: v1.5 - Added a File menu item for choosing the default display (date or time).
  27.               - Chime and default display selections are now saved in a Preference file.
  28.               - Application now handles an AEQuit so that it properly exits when asked 
  29.                 to quit from another app.
  30. 3/13/97: v1.6 - Preferences now use a dialog for selections, and added choice for chiming
  31.                 once or chiming number of hours.
  32. 3/14/97: v1.7 - Added a new style option in the preferences.
  33. 4/29/97: v1.8 - Fixed bug for chiming at 12:00 and midnight, and does CheckMachine first now.
  34.                 Added error dialog when quiting application on an error.
  35. 6/23/97: v1.9 - Added preference for 12-hour or 24-hour clock.
  36.                 
  37. CornerClock ©Bill Catambay, 1997,  bill@catambay.com
  38. All rights reserved worldwide.
  39. }
  40.  
  41. Program CornerClock;
  42. {$NR+}
  43.  
  44. Uses 
  45.     Toolbox, Sound, Resources, Icons;
  46.     
  47. Const
  48.     sAbout = 0;
  49.     sChime = 3;
  50.     kDone = 1;
  51.     kCancel = 2;
  52.     kDisplayDate = 6;
  53.     kDisplayTime = 7;
  54.     kNoChime = 8;
  55.     kChimeOnce = 9;
  56.     kChimeMultiple = 10;
  57.     kBlackWhite = 12;
  58.     kYellowBlack = 13;
  59.     kBWIcon = 14;
  60.     kYBIcon = 15;
  61.     kHour12 = 23;
  62.     kHour24 = 24;
  63.     iDate = 1;
  64.     iTime = 2;
  65.     iForce = 3;
  66.     iPreferences = 5;
  67.     iQuit = 7;
  68.     mApple = 128;
  69.     mFile = 129;
  70.     mEdit = 130;
  71.  
  72. Type
  73.     chimeChoices    =    (noChime, chimeOnce, chimeMultiple);
  74.     displayChoices    =    (displayDate, displayTime);
  75.     styleChoices    =    (blackOnWhite, yellowOnBlack);
  76.     timeChoices        =    (hour12, hour24);
  77.     PrefsRec    =    record
  78.         chimeChoice:    chimeChoices;
  79.         displayChoice:    displayChoices;
  80.         styleChoice:    styleChoices;
  81.         timeChoice:        timeChoices;
  82.         reserved:        packed array[1..18] of integer;
  83.         end;
  84.     PrefsPtr    =    ^PrefsRec;
  85.     PrefsHandle =    ^PrefsPtr;
  86.     
  87. Var
  88.     AppleMenu, FileMenu, 
  89.     EditMenu:                 MenuHandle;
  90.     ClockPort:                 CGrafPtr;
  91.     NUMs:                     array[0..10] of CIconHandle;
  92.     running:                 Boolean;
  93.     ClockRect:                 array[0..3] of Rect;
  94.     Corner:                 Rect;
  95.     styleChoice:            styleChoices;
  96.     displayChoice:             displayChoices;
  97.     timeChoice:             timeChoices;
  98.     dispStat:                 displayChoices;
  99.     bkGnd:                     RgnHandle;
  100.     chimes:                 integer;
  101.     chimeStart:             longint;
  102.     chimeChoice:             chimeChoices;
  103.     timerStart:             longint;
  104.     gBackground:             boolean;
  105.     sounds:                 array[0..3] of SndListHandle;
  106.     sndChans:                 array[0..3] of SndChannelPtr;
  107.     backupChan:             SndChannelPtr;
  108.     forceChime:             boolean;
  109.     fRefnum,vRefnum:         integer;
  110.     gOSErr:                 OSErr;
  111.     
  112. Function UDec(i,len: integer): str255;
  113.  
  114. Var
  115.     str: str255;
  116.     
  117.     begin
  118.     numToString(i,str);
  119.     while length(str) < len do
  120.         str := '0' + str;
  121.     UDec := str;
  122.     end;
  123.     
  124. Procedure Die(str: str255);
  125.  
  126.     begin
  127.       ParamText(str,'','','');
  128.     Alert(128,nil);
  129.     ExitToShell;
  130.     end;
  131.  
  132. Procedure CheckMachine;
  133.  
  134. Var
  135.     sysEnv: SysEnvRec;
  136.     i: integer;
  137.     
  138.     begin
  139.     i := SysEnvirons(curSysEnvVers, sysEnv);
  140.     if i <> noErr then
  141.         Die('Error '+udec(i,3)+' while loading system environment');
  142.     if not sysEnv.hasColorQD then
  143.         Die('CornerClock requires ColorQuickDraw to run.');
  144.     if sysEnv.systemVersion < $700 then
  145.         Die('CornerClock requires Mac OS 7.0 or higher to run.');
  146.     end;
  147.  
  148. Procedure OpenClockPort;
  149.  
  150.     begin
  151.     ClockPort := CGrafPtr(NewPtrClear(sizeof(CGrafPort)));
  152.     if ClockPort = NIL then
  153.         Die('Error occurred trying to create the Clock port');
  154.     OpenCPort(ClockPort);
  155.     end;
  156.  
  157. Procedure SetupMenu;
  158.  
  159.     begin
  160.     ClearMenuBar;
  161.     AppleMenu := GetMenu(mApple);
  162.     InsertMenu(AppleMenu,0);
  163.     AppendResMenu(AppleMenu,'DRVR');
  164.     FileMenu := GetMenu(mFile);
  165.     InsertMenu(FileMenu,0);
  166.     EditMenu := GetMenu(mEdit);
  167.     InsertMenu(EditMenu,0);
  168.     DrawMenuBar;
  169.     end;
  170.  
  171. Procedure LoadIcons;
  172.  
  173. Var
  174.     i: integer;
  175.     
  176.     begin
  177.     for i := 0 to 10 do
  178.         NUMs[i] := GetCIcon((1+integer(styleChoice))*1000 + i);
  179.     end;
  180.  
  181. Procedure SetupRects;
  182.  
  183. Var
  184.     rgn: RgnHandle;
  185.     r: Rect;
  186.     
  187.     begin
  188.     SetRect(ClockRect[0], 2,2,10,10);
  189.     SetRect(ClockRect[1], 8,2,16,10);
  190.     SetRect(ClockRect[2], 2,10,10,18);
  191.     SetRect(ClockRect[3], 8,10,16,18);
  192.     bkGnd := NewRgn;
  193.     SetRect(corner,0,0,16,19);
  194.     RectRgn(bkGnd,corner);
  195.     UnionRect(ClockRect[0], ClockRect[3], r);
  196.     r.bottom := r.bottom - 1;
  197.     r.right := r.right - 2;
  198.     rgn := NewRgn;
  199.     RectRgn(rgn, r);
  200.     DiffRgn(bkGnd, rgn, bkGnd);
  201.     DisposeRgn(rgn);
  202.     end;
  203.  
  204. Function SavePrefs: OSErr;
  205.  
  206. Var
  207.     myPrefs:    PrefsHandle;
  208.     
  209.     Procedure Check(result: OSErr; isResource: boolean);
  210.  
  211.         begin
  212.         if result <> noErr then 
  213.             begin
  214.             if myPrefs <> nil then
  215.                 if isResource then
  216.                     ReleaseResource(Handle(myPrefs))
  217.                 else
  218.                     DisposeHandle(Handle(myPrefs));
  219.             SavePrefs := result;
  220.             exit(SavePrefs);
  221.             end;
  222.         end;
  223.         
  224.     begin
  225.     myPrefs := PrefsHandle(GetResource('pref', 128));
  226.     if myPrefs = NIL then 
  227.         begin
  228.         myPrefs := PrefsHandle(NewHandleClear(sizeof(PrefsRec)));
  229.         Check(MemError, false);
  230.         AddResource(handle(myPrefs), 'pref', 128, 'Defaults');
  231.         Check(ResError, false);
  232.         end;
  233.     myPrefs^^.chimeChoice := chimeChoice;
  234.     myPrefs^^.displayChoice := displayChoice;
  235.     myPrefs^^.styleChoice := styleChoice;
  236.     myPrefs^^.timeChoice := timeChoice;
  237.     ChangedResource(Handle(myPrefs));
  238.     Check(ResError, true);
  239.     UpdateResFile(CurResFile);
  240.     Check(ResError, true);
  241.     ReleaseResource(Handle(myPrefs));
  242.     SavePrefs := noErr;
  243.     end; { of SavePrefs }
  244.     
  245. Function LoadPrefs: OSerr;
  246.  
  247. Var
  248.     myPrefs:    PrefsHandle;
  249.     
  250.     begin
  251.     myPrefs := PrefsHandle(GetResource('pref',128));
  252.     if myPrefs = NIL then
  253.         begin
  254.         chimeChoice := chimeMultiple;
  255.         displayChoice := displayTime;
  256.         styleChoice := yellowOnBlack;
  257.         timeChoice := hour12;
  258.         LoadPrefs := SavePrefs;
  259.         end
  260.     else
  261.         begin
  262.         chimeChoice := myPrefs^^.chimeChoice;
  263.         displayChoice := myPrefs^^.displayChoice;
  264.         styleChoice := myPrefs^^.styleChoice;
  265.         timeChoice := myPrefs^^.timeChoice;
  266.         ReleaseResource(handle(myPrefs));
  267.         LoadPrefs := noErr;
  268.         end;
  269.     end; { of LoadPrefs }
  270.  
  271. Function OpenPrefs(var fRefnum: integer; var vRefnum: integer; prefName: Str255): OSerr;
  272.  
  273. Var
  274.     err:        OSerr;
  275.     DirID:        longint;
  276.     fileSpec:    FSSpec;
  277.  
  278.     begin
  279.     Err := FindFolder(kOnSystemDisk, kPreferencesFolderType,
  280.         kCreateFolder, vRefNum, DirID);
  281.     if Err <> noErr then
  282.         begin
  283.         openPrefs := err;
  284.         exit(openPrefs);
  285.         end;
  286.     Err := FSMakeFSSpec(vRefNum, DirID, prefName, fileSpec);
  287.     if (err <> Noerr) and (err <> fnfErr) then
  288.         begin
  289.         openPrefs := err;
  290.         exit(openPrefs);
  291.         end;
  292.     if Err = fnfErr then { not there so create it }
  293.         begin
  294.         Err := FSpCreate (fileSpec, 'CCLK', 'pref', 0);
  295.         if err <> Noerr then
  296.             begin
  297.             openPrefs := err;
  298.             exit(openPrefs);
  299.             end;
  300.         end;
  301.     fRefnum := FSpOpenResFile(fileSpec, fsCurPerm);
  302.     if fRefnum < 0 then
  303.         begin
  304.         FSpCreateResFile(fileSpec, 'CCLK', 'pref', smSystemScript);
  305.         err := ResError;
  306.         if err <> Noerr then
  307.             begin
  308.             openPrefs := err;
  309.             exit(openPrefs);
  310.             end;
  311.         fRefnum := FSpOpenResFile(fileSpec, fsCurPerm);
  312.         end;
  313.     err := ResError;
  314.     if err <> Noerr then
  315.         begin
  316.         openPrefs := err;
  317.         exit(openPrefs);
  318.         end;
  319.     openPrefs := LoadPrefs;
  320.     end;
  321.  
  322. Function GotRequiredParams (var theAppleEvent: AppleEvent): OSErr;
  323.  
  324. Var
  325.     myErr: OSErr;
  326.     returnedType: DescType;
  327.     actualSize: Size;
  328.  
  329.     Begin
  330.     myErr := AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard, returnedType, 
  331.         Nil, 0, actualSize);
  332.     If myErr = errAEDescNotFound Then
  333.         GotRequiredParams := noErr
  334.     Else If myErr = noErr Then
  335.         GotRequiredParams := errAEParamMissed;
  336.     End;    { of GotRequiredParams }
  337.  
  338. Function HandleQuitEvent(var theAppleEvent: AppleEvent; var reply: AppleEvent;
  339.                            handlerRefcon: LongInt): OSErr;
  340.     
  341.     Begin
  342.     gOSErr := GotRequiredParams(theAppleEvent);
  343.     If gOSErr = noErr Then
  344.         running := false;
  345.     if (reply.dataHandle = NIL) | (handlerRefcon = 0) then  ; { read variable to eliminate compiler warning }
  346.     HandleQuitEvent := gOSErr;
  347.     End;    { of MyHandleQuiteEvent }
  348.  
  349. Procedure AdjustMenu;
  350.  
  351. Var
  352.     err:    OSErr;
  353.     
  354.     begin
  355.     if chimeChoice = noChime then
  356.         begin
  357.         err := SndDisposeChannel(backupChan, True);
  358.         backupChan := NIL;
  359.         DisableItem(FileMenu, iForce);
  360.         end
  361.     else
  362.         begin
  363.         chimes := 0;
  364.         chimeStart := 0;
  365.         forceChime := False;
  366.         EnableItem(FileMenu, iForce);
  367.         end;
  368.     end; { AdjustMenu }
  369.     
  370. Procedure InitAppl;
  371.  
  372. Var
  373.     i: integer;
  374.     err: OSErr;
  375.     
  376.     begin
  377.     OpenClockPort;
  378.     SetupMenu;
  379.     SetupRects;
  380.     running := true;
  381.     chimes := 0;
  382.     chimeStart := 0;
  383.     forceChime := False;
  384.     gBackground := false;
  385.     for i := sAbout to sChime do
  386.         begin
  387.         sounds[i] := SndListHandle(GetResource(soundListRsrc,128 + i));
  388.         HLockHi(Handle(sounds[i]));
  389.         sndChans[i] := NIL;
  390.         end;
  391.     backupChan := NIL;
  392.     err := OpenPrefs(fRefnum,vRefnum,'CornerClock Preferences');
  393.     if err <> noErr then
  394.         Die('Error '+udec(err,3)+' while trying to open the preferences');
  395.     dispStat := displayChoice;
  396.     LoadIcons;
  397.     AdjustMenu;
  398.     gOSErr := AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
  399.         @HandleQuitEvent, 0, false);
  400.     end;
  401.  
  402. Procedure DoSound(sndID: integer);
  403.  
  404. Var
  405.     err: OSErr;
  406.     sndCmd: SndCommand;
  407.     sndHead: SoundHeaderPtr;
  408.     SndChanStat: SCStatus;
  409.     
  410.     begin
  411.     if sounds[sndID] = NIL then
  412.         begin
  413.         sysBeep(1);
  414.         exit(DoSound);
  415.         end;
  416.     if (sndChans[sndID] <> NIL) and (backupChan <> NIL) then
  417.         begin
  418.         err := SndDisposeChannel(backupChan, True);
  419.         backupChan := NIL;
  420.         end;
  421.     if sndChans[sndID] <> NIL then
  422.         begin
  423.         backupChan := sndChans[sndID];
  424.         sndChans[sndID] := NIL;
  425.         end;
  426.     err := SndNewChannel(sndChans[sndID], sampledSynth, 0, NIL);
  427.     if (err <> noErr) or (sndChans[sndID] = NIL) then
  428.         begin
  429.         sysBeep(1);
  430.         exit(DoSound);
  431.         end;
  432.     sndHead := SoundHeaderPtr(longint(sounds[sndID]^) + 20);
  433.     sndCmd.cmd := bufferCmd;
  434.     sndCmd.param1 := 0;
  435.     sndCmd.param2 := ORD4(sndHead);
  436.     err := SndDoCommand(sndChans[sndID], sndCmd, false);
  437.     err := SndChannelStatus(sndChans[sndID], sizeof(SndChanStat), @SndChanStat);
  438.     if err <> noErr then
  439.         begin
  440.         sysBeep(1);
  441.         err := SndDisposeChannel(sndChans[sndID], True);
  442.         sndChans[sndID] := NIL;
  443.         exit(DoSound);
  444.         end;
  445.     end;
  446.     
  447. Procedure DoAbout;
  448.  
  449. Var
  450.     p: GrafPtr;
  451.     d: DialogPtr;
  452.     
  453.     begin
  454.     GetPort(p);
  455.     d := GetNewDialog(128, NIL, WindowPtr(-1));
  456.     if d = NIL then
  457.         die('Error while reading dialog resource #128');
  458.     DrawDialog(d);
  459.     DoSound(sAbout);
  460.     repeat until Button;
  461.     DisposeDialog(d);
  462.     SetPort(p);
  463.     FlushEvents(mDownMask, 0);
  464.     end;
  465.  
  466. Procedure SetRadioItem(dlog: DialogPtr; itemNum: integer; on: boolean);
  467.  
  468. Var
  469.     iType:         integer;
  470.     iHandle:    Handle;
  471.     iRect:        Rect;
  472.  
  473.     begin
  474.     GetDialogItem(dlog,itemNum,iType,iHandle,iRect);
  475.     if on then
  476.         SetControlValue(ControlHandle(iHandle),1)
  477.     else
  478.         SetControlValue(ControlHandle(iHandle),0);
  479.     end;
  480.  
  481. Procedure ChangeDisplay(newValue:    displayChoices;
  482.                         dlg:        dialogPtr);
  483.                       
  484.     begin
  485.     SetRadioItem(dlg, kDisplayDate + integer(displayChoice), FALSE);
  486.     displayChoice := newValue;
  487.     SetRadioItem(dlg, kDisplayDate + integer(displayChoice),TRUE);
  488.     end;
  489.  
  490. Procedure ChangeStyle(newValue:    styleChoices;
  491.                       dlg:        dialogPtr);
  492.                       
  493.     begin
  494.     SetRadioItem(dlg, kBlackWhite + integer(styleChoice), FALSE);
  495.     styleChoice := newValue;
  496.     SetRadioItem(dlg, kBlackWhite + integer(styleChoice),TRUE);
  497.     end;
  498.  
  499. Procedure ChangeTime(newValue:    timeChoices;
  500.                       dlg:        dialogPtr);
  501.                       
  502.     begin
  503.     SetRadioItem(dlg, kHour12 + integer(timeChoice), FALSE);
  504.     timeChoice := newValue;
  505.     SetRadioItem(dlg, kHour12 + integer(timeChoice),TRUE);
  506.     end;
  507.  
  508. Procedure ChangeChime(newValue:    chimeChoices;
  509.                       dlg:        dialogPtr);
  510.                       
  511.     begin
  512.     SetRadioItem(dlg, kNoChime + integer(chimeChoice), FALSE);
  513.     chimeChoice := newValue;
  514.     SetRadioItem(dlg, kNoChime + integer(chimeChoice),TRUE);
  515.     end;
  516.  
  517. Procedure SwitchView;
  518.  
  519.     begin
  520.     if dispStat = displayDate then
  521.         dispStat := displayTime 
  522.     else
  523.         dispStat := displayDate;
  524.     doSound(1 + integer(dispStat));
  525.     if dispStat <> displayChoice then
  526.         timerStart := TickCount;
  527.     end;
  528.  
  529. Procedure ForceView(newView: displayChoices);
  530.  
  531.     begin
  532.     dispStat := newView;
  533.     doSound(1 + integer(dispStat));
  534.     if dispStat <> displayChoice then
  535.         timerStart := TickCount;
  536.     end;
  537.         
  538. Procedure DoPreferences;
  539.  
  540. Var
  541.     p: GrafPtr;
  542.     d: DialogPtr;
  543.     item: integer;
  544.     saveChime: ChimeChoices;
  545.     saveDisplay: DisplayChoices;
  546.     saveStyle: StyleChoices;
  547.     saveTime: TimeChoices;
  548.     
  549.     begin
  550.     GetPort(p);
  551.     d := GetNewDialog(129, NIL, WindowPtr(-1));
  552.     if d = NIL then
  553.         die('Error while reading dialog resource #129');
  554.     saveChime := chimeChoice;
  555.     saveDisplay := displayChoice;
  556.     saveStyle := styleChoice;
  557.     saveTime := timeChoice;
  558.     case chimeChoice of
  559.     noChime:        SetRadioItem(d, kNoChime, TRUE);
  560.     chimeOnce:        SetRadioItem(d, kChimeOnce, TRUE);
  561.     chimeMultiple:    SetRadioItem(d, kChimeMultiple, TRUE);
  562.     {CASE}            end;
  563.     case displayChoice of
  564.     displayDate:    SetRadioItem(d, kDisplayDate, TRUE);
  565.     displayTime:    SetRadioItem(d, kDisplayTime, TRUE);
  566.     {CASE}            end;
  567.     case styleChoice of
  568.     blackOnWhite:    SetRadioItem(d, kBlackWhite, TRUE);
  569.     yellowOnBlack:    SetRadioItem(d, kYellowBlack, TRUE);
  570.     {CASE}            end;
  571.     case timeChoice of
  572.     hour12:            SetRadioItem(d, kHour12, TRUE);
  573.     hour24:            SetRadioItem(d, kHour24, TRUE);
  574.     {CASE}            end;
  575.     ShowWindow(d);
  576.     repeat
  577.         ModalDialog(NIL, item);
  578.         case item of
  579.             kDisplayDate:    ChangeDisplay(displayDate, d);
  580.             kDisplayTime:    ChangeDisplay(displayTime, d);
  581.             kNoChime:        ChangeChime(noChime, d);
  582.             kChimeOnce:        ChangeChime(chimeOnce, d);
  583.             kChimeMultiple:    ChangeChime(chimeMultiple, d);
  584.             kBlackWhite:    ChangeStyle(blackOnWhite, d);
  585.             kYellowBlack:    ChangeStyle(yellowOnBlack, d);
  586.             kHour12:        ChangeTime(hour12, d);
  587.             kHour24:        ChangeTime(hour24, d);
  588.             otherwise;
  589.         {CASE}         end;
  590.     until (item = kCancel) or (item = kDone);
  591.     if item = kCancel then
  592.         begin
  593.         chimeChoice := saveChime;
  594.         displayChoice := saveDisplay;
  595.         styleChoice := saveStyle;
  596.         timeChoice := saveTime;
  597.         end
  598.     else
  599.         begin
  600.         AdjustMenu;
  601.         LoadIcons;
  602.         ForceView(displayChoice);
  603.         SavePrefs;
  604.         end;
  605.     DisposeDialog(d);
  606.     SetPort(p);
  607.     FlushEvents(mDownMask, 0);
  608.     end; { of DoPreferences }
  609.     
  610. Procedure DoMenu(SelMenu: longint);
  611.  
  612. Var
  613.     item,i: integer;
  614.     s:         Str255;
  615.     
  616.     begin
  617.     item := LoWord(SelMenu);
  618.     case HiWord(SelMenu) of
  619.         mApple:    if item = 1 then
  620.                     DoAbout
  621.                 else
  622.                     begin
  623.                     GetMenuItemText(AppleMenu, item, s);
  624.                     i := OpenDeskAcc(s);
  625.                     end;
  626.         mFile:    case item of
  627.                 iDate:    ForceView(displayDate);
  628.                 iTime:    ForceView(displayTime);
  629.                 iForce:    if chimeChoice <> noChime then
  630.                             forceChime := True;
  631.                 iPreferences:
  632.                         DoPreferences;
  633.                 iQuit:    running := false;
  634.                 {CASE}    end;
  635.     {CASE}        end;
  636.     HiliteMenu(0);
  637.     end;
  638.  
  639. Procedure UpdateWindow(wp: WindowPtr);
  640.  
  641.     begin
  642.     SetPort(wp);
  643.     BeginUpdate(wp);
  644.     EndUpdate(wp);
  645.     end;
  646.  
  647. Procedure DrawDigit(upper,lower: integer; upShow10, loShow10: boolean);
  648.  
  649. Var
  650.     p: GrafPtr;
  651.     
  652.     begin
  653.     GetPort(p);
  654.     SetPort(GrafPtr(ClockPort));
  655.     ForeColor(blackColor);
  656.     PaintRgn(bkGnd);
  657.     if (upper >= 10) | upShow10 then
  658.         PlotCIcon(ClockRect[0], NUMs[ (upper div 10) mod 10])
  659.     else
  660.         PlotCIcon(ClockRect[0], NUMs[10]);
  661.     PlotCIcon(ClockRect[1], NUMs[upper mod 10]);
  662.     if (lower >= 10) | loShow10 then
  663.         PlotCIcon(ClockRect[2], NUMs[(lower div 10) mod 10])
  664.     else
  665.         PlotCIcon(ClockRect[2], NUMs[10]);
  666.     PlotCIcon(ClockRect[3], NUMs[lower mod 10]);
  667.     SetPort(p);
  668.     end;
  669.  
  670. Procedure DrawClock;
  671.  
  672. Const    
  673.     chimeMinute = 0;
  674.     
  675. Var
  676.     dt: DateTimeRec;
  677.     p: GrafPtr;
  678.     pt: point;
  679.     
  680.     begin
  681.     GetPort(p);
  682.     SetPort(GrafPtr(ClockPort));
  683.     GetTime(dt);
  684.     GetMouse(pt);
  685.     if PtInRect(pt, corner) and (dispStat = displayChoice) then
  686.         SwitchView;
  687.     if (dispStat <> displayChoice) & (timerStart + 300 < TickCount) then
  688.         SwitchView;
  689.     ForeColor(blackColor);
  690.     PaintRgn(bkGnd);
  691.     case dispStat of 
  692.         displayDate:    DrawDigit(dt.month, dt.day, false, false);
  693.         displayTime:    if (timeChoice = Hour24) or (dt.hour = 12) then
  694.                             DrawDigit(dt.hour, dt.minute, false, true)
  695.                         else
  696.                             DrawDigit(dt.hour mod 12, dt.minute, false, true);
  697.     {CASE}                end;
  698.     if chimeChoice <> noChime then
  699.         begin
  700.         if ((dt.minute = chimeMinute) or forceChime) and (chimes = 0) then
  701.             begin
  702.             if chimeChoice = chimeMultiple then
  703.                 begin
  704.                 chimes := dt.hour mod 12;
  705.                 if chimes = 0 then
  706.                     chimes := 12;
  707.                 end
  708.             else
  709.                 chimes := 1;
  710.             end;
  711.         if (chimes > 0) & ((chimeStart = 0) | (chimeStart + 120 < TickCount)) then
  712.             begin
  713.             doSound(sChime);
  714.             chimeStart := TickCount;
  715.             dec(chimes);
  716.             if chimes = 0 then
  717.                 dec(chimes);
  718.             end
  719.         else if (chimes = -1) & (dt.minute <> chimeMinute) then
  720.             begin
  721.             chimes := 0;
  722.             forceChime := False;
  723.             chimeStart := 0;
  724.             end;
  725.         end;
  726.     SetPort(p);
  727.     end;
  728.  
  729. Procedure MainLoop;
  730.  
  731. Var
  732.     event: EventRecord;
  733.     dw: WindowPtr;
  734.     ascii: char;
  735.     sleep: longint;
  736.     i: integer;
  737.     err: OSErr;
  738.     
  739.     begin
  740.     repeat
  741.         DrawClock;
  742.         if chimes > 0 then
  743.             sleep := 1
  744.         else
  745.             sleep := 20;
  746.         if WaitNextEvent(everyEvent, event, sleep, NIL) then
  747.             case event.what of
  748.                 mouseDown:    case FindWindow(event.where, dw) of
  749.                                 inMenuBar:    DoMenu(MenuSelect(event.where));
  750.                             {CASE}            end;
  751.                 keyDown:    begin
  752.                             ascii := chr(BAnd(event.message,charCodeMask));
  753.                             if BAnd(event.modifiers,cmdKey) > 0 then
  754.                                 DoMenu(MenuKey(ascii));
  755.                             end;
  756.                 updateEvt:    UpdateWindow(WindowPtr(event.message));
  757.                 osEvt:        if BAnd(brotl(event.message,8),$FF) = suspendResumeMessage then
  758.                                 gBackground := BAnd(event.message,resumeFlag) = 0;
  759.                 kHighLevelEvent:
  760.                             gOSErr := AEProcessAppleEvent(Event);
  761.             {CASE}            end;
  762.     until not running;
  763.     if SavePrefs <> noErr then
  764.         sysBeep(30);
  765.     DisposeRgn(bkGnd);    
  766.     for i := 0 to 2 do
  767.         begin
  768.         HUnLock(Handle(sounds[i]));
  769.         DisposeHandle(Handle(sounds[i]));
  770.         err := SndDisposeChannel(sndChans[i], True);
  771.         end;
  772.     if backupChan <> NIL then
  773.         err := SndDisposeChannel(backupChan, True);
  774.     end;
  775.  
  776. begin
  777. InitToolbox;
  778. CheckMachine;
  779. FlushEvents(everyEvent, 0);
  780. InitAPPL;
  781. MainLoop;
  782. end.