-- file DisplayControl.Mesa
-- last edited by Sandman, July 1, 1980  10:10 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDisplay USING [DCBchainHead, DCBnil],
  AltoFileDefs USING [FP],
  DirectoryDefs USING [EnumerateDirectory],
  DisplayDefs USING [
    BlinkCursor, DeleteDisplayData, DisplayOff, DisplayOn, GetTypeScript,
    InitDisplay, SetFont, SetTypeScript],
  FontDefs USING [CreateFont, FontHandle],
  FrameDefs USING [GlobalFrame, SelfDestruct, UnNew],
  ImageDefs USING [
    AddCleanupProcedure, AddFileRequest, AllReasons, CleanupItem,
    CleanupProcedure, FileRequest, RemoveCleanupProcedure],
  ProcessDefs USING [InitializeCondition, MsecToTicks, SetTimeout],
  SDDefs USING [sAddFileRequest, SD],
  SegmentDefs USING [
    Append, DefaultBase, DefaultPages, DeleteFileSegment, FileHandle,
    FileSegmentHandle, InsertFile, NewFile, NewFileSegment, Read, ReleaseFile,
    UnlockFile, Write],
  StreamDefs USING [
    CloseDiskStream, CreateByteStream, GetIndex, OpenDiskStream, SetIndex,
    StreamError, StreamHandle, StreamIndex, TruncateDiskStream],
  StringDefs USING [EquivalentString],
  Storage USING [Node, CopyString, Free, FreeString];

DisplayControl: MONITOR
  IMPORTS
    DirectoryDefs, DisplayDefs, FrameDefs, FontDefs, ImageDefs, ProcessDefs,
    SegmentDefs, StreamDefs, StringDefs, Storage
  EXPORTS DisplayDefs =
  BEGIN

  Data: TYPE = RECORD [
    font: FontDefs.FontHandle,
    fontseg: SegmentDefs.FileSegmentHandle,
    initialize, useTypescript, imaging, stopCursor: BOOLEAN,
    cursorWait: CONDITION,
    cursorProcess: PUBLIC PROCESS,
    cleanupitem: ImageDefs.CleanupItem,
    requests: POINTER TO Requests];

  Requests: TYPE = RECORD [mesafont, sysfont, typescript: ImageDefs.FileRequest];

  data: POINTER TO Data;

  CreateRequests: PROCEDURE =
    BEGIN OPEN SegmentDefs, Storage;
    requests: POINTER TO Requests ← Node[SIZE[Requests]];
    requests.mesafont ←
      [link: NIL, file:, access: Read, name: CopyString["MesaFont.al."L]];
    requests.sysfont ←
      [link: @requests.mesafont, file:, access: Read,
	name: CopyString["SysFont.al."L]];
    requests.typescript ←
      [link: @requests.sysfont, file:, access: Read + Write + Append,
	name: CopyString["Mesa.Typescript."L]];
    data.requests ← requests;
    RETURN
    END;

  DeleteRequests: PROCEDURE =
    BEGIN OPEN Storage;
    FreeString[data.requests.mesafont.name];
    FreeString[data.requests.sysfont.name];
    FreeString[data.requests.typescript.name];
    Free[data.requests];
    RETURN
    END;

  CreateData: PROCEDURE =
    BEGIN OPEN ImageDefs, data;
    data ← Storage.Node[SIZE[Data]];
    cleanupitem ← [link:, mask: AllReasons, proc: Cleanup];
    initialize ← useTypescript ← stopCursor ← TRUE;
    ProcessDefs.InitializeCondition[@cursorWait, ProcessDefs.MsecToTicks[450]];
    RETURN
    END;

  DeleteData: PROCEDURE =
    BEGIN
    ImageDefs.RemoveCleanupProcedure[@data.cleanupitem];
    Storage.Free[data];
    RETURN
    END;

  Cleanup: ImageDefs.CleanupProcedure =
    BEGIN OPEN ImageDefs, data;
    file: SegmentDefs.FileHandle;
    i: CARDINAL;
    si: StreamDefs.StreamIndex;
    ts: StreamDefs.StreamHandle ← DisplayDefs.GetTypeScript[];
    SELECT why FROM
      Finish, Abort, Save =>
	BEGIN
	IF why # Save THEN AltoDisplay.DCBchainHead↑ ← AltoDisplay.DCBnil;
	IF ~initialize AND ts # NIL THEN
	  BEGIN
	  StreamDefs.TruncateDiskStream[ts];
	  DisplayDefs.SetTypeScript[NIL];
	  END;
	IF why = Save AND ~initialize THEN
	  BEGIN
	  DisplayDefs.DisplayOff[black];
	  font.destroy[font];
	  SegmentDefs.DeleteFileSegment[fontseg];
	  END;
	IF why # Save THEN RETURN;
	CreateRequests[];
	imaging ← SDDefs.SD[SDDefs.sAddFileRequest] # 0;
	requests.mesafont.file ← NIL;
	IF imaging THEN ImageDefs.AddFileRequest[@requests.mesafont];
	requests.sysfont.file ← NIL;
	IF imaging THEN ImageDefs.AddFileRequest[@requests.sysfont];
	requests.typescript.file ← NIL;
	IF imaging AND useTypescript THEN
	  ImageDefs.AddFileRequest[@requests.typescript];
	END;
      Restore =>
	BEGIN OPEN SegmentDefs;
	IF (file ← requests.mesafont.file) = NIL THEN file ← requests.sysfont.file
	ELSE
	  BEGIN
	  f: FileHandle = requests.sysfont.file;
	  UnlockFile[f];
	  ReleaseFile[f];
	  END;
	fontseg ← NewFileSegment[file, DefaultBase, DefaultPages, Read];
	font ← FontDefs.CreateFont[fontseg];
	IF initialize THEN
	  BEGIN initialize ← FALSE; DisplayDefs.InitDisplay[24, 14, 20, font] END
	ELSE BEGIN DisplayDefs.SetFont[font]; DisplayDefs.DisplayOn[] END;
	IF ~useTypescript THEN BEGIN DeleteRequests[]; RETURN END;
	IF (file ← requests.typescript.file) = NIL THEN
	  file ← NewFile[requests.typescript.name, Read + Write + Append];
	DisplayDefs.SetTypeScript[
	  StreamDefs.CreateByteStream[file, Read + Write + Append]];
	DeleteRequests[];
	END;
      Checkpoint =>
	BEGIN
	IF ts # NIL THEN StreamDefs.CloseDiskStream[ts];
	DisplayDefs.DisplayOff[white];
	END;
      Continue =>
	BEGIN
	DisplayDefs.DisplayOn[];
	IF ts # NIL THEN StreamDefs.OpenDiskStream[ts];
	END;
      Restart =>
	BEGIN OPEN StreamDefs;
	DisplayDefs.DisplayOn[];
	IF ts # NIL THEN
	  BEGIN
	  OpenDiskStream[ts ! StreamError => IF error = StreamEnd THEN RESUME ];
	  ts.reset[ts]
	  END;
	END;
      InLd => IF ts # NIL THEN StreamDefs.OpenDiskStream[ts];
      OutLd =>
	BEGIN OPEN StreamDefs;
	IF ts = NIL THEN RETURN;
	si ← GetIndex[ts];
	ts.put[ts, 15C];
	FOR i IN [0..9) DO ts.put[ts, '~] ENDLOOP;
	SetIndex[ts, si];
	CloseDiskStream[ts];
	END;
      ENDCASE;
    RETURN
    END;

  Cursor: ENTRY PROCEDURE =
    BEGIN OPEN data;
    timer: POINTER TO INTEGER ← LOOPHOLE[430B];
    blinktime: INTEGER;
    ProcessDefs.SetTimeout[@cursorWait, ProcessDefs.MsecToTicks[450]];
    DO
      -- forever
      IF blinktime - timer↑ ~IN [0..13] THEN
	BEGIN [] ← DisplayDefs.BlinkCursor[]; blinktime ← timer↑ + 13 END;
      IF stopCursor THEN EXIT;
      WAIT cursorWait;
      ENDLOOP;
    RETURN
    END;

  StartCursor: PUBLIC ENTRY PROCEDURE =
    BEGIN OPEN data;
    IF ~stopCursor THEN RETURN;
    stopCursor ← FALSE;
    cursorProcess ← FORK Cursor[];
    RETURN
    END;

  PokeCursorProcess: PUBLIC ENTRY PROCEDURE RETURNS [BOOLEAN] =
    BEGIN OPEN data;
    IF stopCursor THEN RETURN[FALSE];
    NOTIFY cursorWait;
    stopCursor ← TRUE;
    RETURN[TRUE]
    END;

  StopCursor: PUBLIC PROCEDURE =
    BEGIN OPEN data; IF PokeCursorProcess[] THEN JOIN cursorProcess; RETURN END;

  DestroyDisplay: PUBLIC PROCEDURE =
    BEGIN OPEN FrameDefs;
    StopCursor[];
    DisplayDefs.DisplayOff[white];
    Cleanup[Finish];
    data.font.destroy[data.font];
    DisplayDefs.DeleteDisplayData[];
    UnNew[GlobalFrame[FontDefs.CreateFont]];
    UnNew[GlobalFrame[DisplayDefs.SetTypeScript]];
    DeleteData[];
    SelfDestruct[];
    RETURN
    END;

  -- file requests


  ProcessFileRequests: PROCEDURE [rHead: POINTER TO ImageDefs.FileRequest] =
    BEGIN OPEN AltoFileDefs;

    checkone: PROCEDURE [fp: POINTER TO FP, dname: STRING] RETURNS [BOOLEAN] =
      BEGIN
      r: POINTER TO ImageDefs.FileRequest;
      prev: POINTER TO ImageDefs.FileRequest ← NIL;
      FOR r ← rHead, r.link UNTIL r = NIL DO
	IF StringDefs.EquivalentString[dname, r.name] THEN
	  BEGIN
	  IF r.file = NIL THEN r.file ← SegmentDefs.InsertFile[fp, r.access]
	  ELSE r.file.fp ← fp↑;
	  IF prev = NIL THEN rHead ← r.link ELSE prev.link ← r.link;
	  END
	ELSE prev ← r;
	ENDLOOP;
      RETURN[rHead = NIL]
      END;

    DirectoryDefs.EnumerateDirectory[checkone];
    END;

  CreateData[];
  ImageDefs.AddCleanupProcedure[@data.cleanupitem];
  Cleanup[Save];
  IF data.imaging THEN STOP ELSE ProcessFileRequests[@data.requests.typescript];
  Cleanup[Restore];
  StartCursor[];

  END...