


MODULE  TADClock;


(*  Dieses Programm installiert ein nicht verschiebbares Fenster ohne alle  *)
(*  Systemgadgets in der Titelleiste des Workbench-Bildschirms. In diesem   *)
(*  Fenster werden laufend Datum, Uhrzeit und aktuelle Speicherbelegung     *)
(*  angezeigt. Beendet wird das Programm dadurch, daß eine andere Task ihm  *)
(*  eine Nachricht an den "ClockPort" sendet. Dabei hat der "ClockPort" den *)
(*  symbolischen Namen "TADClock-Port", damit man ihn mittels "FindPort"    *)
(*  leicht auffinden kann.                                                  *)
(*                                                                          *)
(*  von Ernst Heinz  /  10.10.1989                                          *)

(* $F-, $R-, $S-, $V- *)




FROM  Arguments    IMPORT  GetArg, NumArgs;

FROM  Arts         IMPORT  Assert, Requester, TermProcedure;

FROM  Conversions  IMPORT  ValToStr;

FROM  Dos          IMPORT  Date, DateStamp, Delay;

FROM  DosSpecials  IMPORT  MakeDateStr, MakeTimeStr;

FROM  Exec         IMPORT  AvailMem, chip, fast, FindPort, GetMsg, MemReqSet,
                           MessagePtr, ReplyMsg;

FROM  ExecSupport  IMPORT  CreatePort, DeletePort;

FROM  Intuition    IMPORT  ActivateWindow, DisplayBeep, WBenchToFront,
                           windowActive, WindowPtr;

FROM  Str          IMPORT  Compare, Concat, Copy, CopyPos;

FROM  WindowLib    IMPORT  CloseWin, FillWin, noBack, noBorder, noClose,
                           noMove, noSize, PlaceWin, SimpleWin, WriteWin;

FROM  SYSTEM       IMPORT  ADDRESS, ADR;




CONST  myPortName = 'TADClock-Port';




TYPE  TimeString = ARRAY[0..7] OF CHAR;




VAR  ClockWin           : WindowPtr;    (*  Zeiger für das Fenster  *)
     ClockPort          : ADDRESS;      (*  Zeiger auf den eigenen Port  *)
     ClockMsg           : MessagePtr;   (*  Zeiger auf erhaltene Nachricht  *)
     MsgNamePtr         : POINTER TO TimeString;
     l                  : INTEGER;
     StopClock          : BOOLEAN;      (*  Flagge für Programmende  *)
     AlarmShown         : BOOLEAN;      (*  Flagge, ob Alarmzeit angezeigt  *)
     FastFree, ChipFree : LONGINT;      (*  die gerade angezeigten Werte  *)
     OldTimeStr         : TimeString;   (*  die gerade angezeigte Zeit  *)
     AlarmTimeStr       : TimeString;   (*  die Alarmuhrzeit  *)
     FastStr, ChipStr   : ARRAY[0..17] OF CHAR;
     InfoStr            : ARRAY[0..60] OF CHAR;




PROCEDURE  MakeMemInfo( VAR str: ARRAY OF CHAR; freeMem: LONGINT );

(*  Wandelt die angegebene Zahl "freeMem" in eine 7-stellige Zeichenkette  *)
(*  um und trägt diese am Ende des "str" ein.                              *)


VAR  err   : BOOLEAN;
     NrStr : ARRAY[0..6] OF CHAR;


BEGIN
 ValToStr(ABS(freeMem),FALSE,NrStr,10,7,'0',err);
 CopyPos(str,NrStr,6)
END  MakeMemInfo;




PROCEDURE  CheckActualInfo;

(*  Überprüft, ob die angezeigten Informationen noch gültig sind und  *)
(*  frischt sie gegebenenfalls auf.                                   *)


VAR  InfoUpdate  : BOOLEAN;    (*  Flagge für Auffrischung der Informationen  *) 
     NewFastFree : LONGINT;
     NewChipFree : LONGINT;
     NewDate     : Date;
     NewDateStr  : ARRAY[0..10] OF CHAR;
     NewTimeStr  : TimeString;



 PROCEDURE  DoAlarm;
 
 (*  Erzeugt einen Systemrequester, um den Benutzer zu alarmieren.  *)

 BEGIN
  IF WBenchToFront() THEN
   FOR l:=1 TO 10 DO DisplayBeep(NIL) END
  END;
  FillWin(ClockWin,1);
  WriteWin(ClockWin,'=TADClock=  Alarm time reached !!',137,7,3,1);
  StopClock := Requester(ADR('**ALARM**  =TADClock=  **ALARM**'),
                         ADR('!! Sleepy user, please wake up !!'),
                         ADR(' Remove clock '),
                         ADR(' Continue '))
 END  DoAlarm;



 PROCEDURE  ShowAlarmInfo;
 
 (*  Zeigt die momentan gesetzte Alarmzeit an !  *)

 VAR  AlarmInfo : ARRAY[0..40] OF CHAR;

 BEGIN
  IF NOT AlarmShown THEN           (*  wird die Alarmzeit schon angezeigt ?  *)
   AlarmInfo := '=TADClock=  ';    (*  nein --> neu anzeigen  *)
   IF AlarmTimeStr[0]=0C THEN
    Concat(AlarmInfo,'No alarm time set !')
   ELSE
    Concat(AlarmInfo,'Alarm time is ');
    Concat(AlarmInfo,AlarmTimeStr)
   END;
   FillWin(ClockWin,1);
   WriteWin(ClockWin,AlarmInfo,137,7,3,1)
  END
 END  ShowAlarmInfo;



 PROCEDURE  MakeInfoStr;

 (*  Erzeugt aus den augenblicklichen Daten die neue Ausgabeinformation.  *)

 BEGIN
  Copy(InfoStr,FastStr);
  Concat(InfoStr,'  ');
  Concat(InfoStr,ChipStr);
  Concat(InfoStr,'  ');
  MakeDateStr(NewDate,NewDateStr);
  Concat(InfoStr,NewDateStr);
  Concat(InfoStr,'  ');
  Concat(InfoStr,NewTimeStr);
  Copy(InfoStr,InfoStr)
 END  MakeInfoStr;



BEGIN                                              (*  Alarmzeit anzeigen ?  *)
 DateStamp(ADR(NewDate));         (*  aktuellen Zeit- & Datumswert bestimmen  *)
 MakeTimeStr(NewDate,NewTimeStr);
 IF Compare(NewTimeStr,AlarmTimeStr)=0 THEN   (*  Alarmzeit erreicht ?  *)
  DoAlarm
 END;
 IF windowActive IN ClockWin^.flags THEN
  ShowAlarmInfo;
  FastFree := 0;   (*  beim nächsten Mal neue Ausgabeinformationen erzeugen  *)
  ChipFree := 0;
  AlarmShown := TRUE;
  RETURN
 END;
 AlarmShown := FALSE;
 InfoUpdate := (Compare(OldTimeStr,NewTimeStr)<>0);     (*  Zeitänderung ?  *)
 OldTimeStr := NewTimeStr;
 NewFastFree := AvailMem(MemReqSet{fast});   (*  aktuelle Speicherbelegung  *)
 NewChipFree := AvailMem(MemReqSet{chip});
 IF NewFastFree#FastFree THEN                (*  Änderungen für Fast-RAM ?  *)
  MakeMemInfo(FastStr,NewFastFree);
  FastFree := NewFastFree;
  InfoUpdate := TRUE
 END;
 IF NewChipFree#ChipFree THEN                (*  Änderungen für Chip-RAM ?  *)
  MakeMemInfo(ChipStr,NewChipFree);
  ChipFree := NewChipFree;
  InfoUpdate := TRUE
 END;
 IF InfoUpdate THEN             (*  Anzeige wegen Änderungen auffrischen ?  *)
  MakeInfoStr;
  WriteWin(ClockWin,InfoStr,1,7,3,1)
 END
END  CheckActualInfo;




PROCEDURE  CleanUp;         (*  die Abschlußprozedur !  *)
 BEGIN
  IF ClockWin#NIL THEN      (*  muß das Fenster geschlossen werden ?  *)
   CloseWin(ClockWin);
   ClockWin := NIL
  END;
  IF ClockPort#NIL THEN             (*  muß der Port entfernt werden ?  *)
   ClockMsg := GetMsg(ClockPort);
   WHILE ClockMsg#NIL DO              (*  ja --> alle Botschaften entfernen  *)
    IF ClockMsg^.node.name#NIL THEN
     ReplyMsg(ClockMsg)               (*  eventuell auch beantworten  *)
    END;
    ClockMsg := GetMsg(ClockPort)
   END;
   DeletePort(ClockPort);           (*  Port nun endgültig löschen  *)
   ClockPort := NIL
  END
 END  CleanUp;




BEGIN
 (*  Ein kurzes Programm-Logo.....  *)
 IF Requester(ADR('=TADClock=  Written by E.Heinz with'),
              ADR('"AmigaTreasures" & "FileTreasures"'),
              NIL,
              ADR(' Continue ')) THEN END;

 ClockWin := NIL;          (*  Initialisierungen !  *)
 ClockPort := NIL;
 FastFree := 0;
 ChipFree := 0;
 FastStr := 'Fast: #';
 ChipStr := 'Chip: #';
 OldTimeStr := '';
 AlarmTimeStr := '';

 TermProcedure(CleanUp);

 (*  Mehr als einmal darf die "TADClock" nicht geöffnet werden !  *)
 Assert(FindPort(ADR(myPortName))=NIL,ADR('"TADClock" already active !'));
 
 (*  Nun den eigenen Port namens "TADClock-Port" einrichten.  *)
 ClockPort := CreatePort(ADR(myPortName),0);
 Assert(ClockPort#NIL,ADR('Cannot create port !'));
 
 (*  Als nächstes die gewünschte Alarmzeit übernehmen.  *)
 IF NumArgs()>0 THEN
  GetArg(1,AlarmTimeStr,l);   (*  beim Starten angegebene Alarmzeit setzen  *)
  IF l#8 THEN
   AlarmTimeStr := ''
  END
 END;
 
 (*  So einfach geht das Öffnen des Fensters mit den "AmigaTreasures" !  *)
 ClockWin := SimpleWin(NIL,'',175,0,411,10,
                       noBack+noBorder+noClose+noMove+noSize);

 (*  Die Hauptschleife, in der das Programm auf Nachrichten an seinem Port  *)
 (*  wartet, sämtliche Informationen auf den neuesten Stand bringt und die  *)
 (*  gesetzte Alarmzeit anzeigt, falls das Fenster aktiviert wird.          *)

 AlarmShown := FALSE;
 StopClock := FALSE;

 WHILE NOT StopClock DO
  CheckActualInfo;                      (*  neuen Ausgabeinformationen ?  *)
  Delay(20);                            (*  die längste Zeit warten .....  *)
  ClockMsg := GetMsg(ClockPort);
  IF ClockMsg#NIL THEN                  (*  Nachricht am Port eingetroffen ?  *)
   MsgNamePtr := ClockMsg^.node.name;   (*  --> Namenszeiger herausholen  *)
   IF MsgNamePtr#NIL THEN               (*  Betrifft dies die Alarmzeit ?  *)
    Copy(AlarmTimeStr,MsgNamePtr^);     (*  ja --> neuen Alarmzeit kopieren  *)
    AlarmShown := FALSE;
    ReplyMsg(ClockMsg);                 (*  Alarmnachricht beantworten !  *)
    PlaceWin(ClockWin,175,0,TRUE);
    ActivateWindow(ClockWin)        (*  Uhrfenster im Vordergrund aktivieren  *)
   ELSE
    StopClock := TRUE        (*  keine Alarmnachricht --> Programm beenden !  *)
   END
  END
 END;
 
 CleanUp 
END  TADClock.
