-- N.Wirth June 1, 1977
-- S.Andler August 24, 1977 10:45 PM
DIRECTORY
FSPDefs: FROM "FSPDefs",
IODefs: FROM "IODefs",
InlineDefs: FROM "InlineDefs",
PupDefs: FROM "PupDefs",
SystemDefs: FROM "SystemDefs",
SegmentDefs: FROM "SegmentDefs",
StreamDefs: FROM "StreamDefs",
StringDefs: FROM "StringDefs",
TeleSilDefs: FROM "TeleSilDefs";

DEFINITIONS FROM
StreamDefs, --
StreamHandle, GetDefaultKey, endof, get
SystemDefs, --
AllocateHeapNode, AllocateHeapString, FreeHeapNode
IODefs, --
DEL, CR, ReadChar, Control?
TeleSilDefs;

------------------------------------------------------------------

TeleSilMain: PROGRAM=
BEGIN
-- A picture is represented by a single circular linked list.
-- Each element represents either a line, an area, or a text
-- string. It is of type Object. Rover is a pointer some
-- element of the chain. Objects are allocated from the heap.
-- Unused objects are freed.

-- External procedures --
-- From TeleSilResident --
CursorPosition: EXTERNAL PROCEDURE RETURNS[Coord];
EraseRectangle: EXTERNAL PROCEDURE[z: Zone];
InitDisplay: EXTERNAL PROCEDURE;
Mark: EXTERNAL PROCEDURE[point: Coord, icon: CursorIcon];
MouseEvent: EXTERNAL PROCEDURE[m: CARDINAL] RETURNS[CARDINAL];
MouseValue: EXTERNAL PROCEDURE RETURNS[INTEGER];
PaintRectangle: EXTERNAL PROCEDURE[f: CARDINAL, z: Zone, g: GrayTone];
PaintString: EXTERNAL PROCEDURE[s:STRING, z: Zone, fno:CARDINAL]
RETURNS [CARDINAL];
SetCursorIcon: EXTERNAL PROCEDURE[icon: CursorIcon] RETURNS[oldIcon: CursorIcon];
SetMousePosition: EXTERNAL PROCEDURE[point: Coord];
SetGridSpacing: EXTERNAL PROCEDURE[gridSpacing: GridSpacing];
ShrinkBM: EXTERNAL PROCEDURE;
-- From TeleSilDisplay --
BitMapDisplay: EXTERNAL PROCEDURE;
ChangeFonts: EXTERNAL PROCEDURE;
Confirm: EXTERNAL PROCEDURE RETURNS[BOOLEAN];
DisplayTicks, EraseTicks: EXTERNAL PROCEDURE;
Error: EXTERNAL PROCEDURE[s: STRING];
FontHeight: EXTERNAL PROCEDURE[fontno: FontNumber] RETURNS[CARDINAL];
FontLoaded: EXTERNAL PROCEDURE[n: CARDINAL] RETURNS[BOOLEAN];
GetString: EXTERNAL PROCEDURE[s: STRING, fno: CARDINAL, ch: CHARACTER]
RETURNS[CARDINAL, CARDINAL];
TypeScriptWindow: EXTERNAL PROCEDURE;
-- From TeleSilIO --
Input: EXTERNAL PROCEDURE;
HardCopy, Output: EXTERNAL PROCEDURE;
-- From TeleSilPup --
AllocateCmd: EXTERNAL PROCEDURE RETURNS[CmdPtr];
CmdWaiting: EXTERNAL PROCEDURE RETURNS[BOOLEAN];
Connect, Disconnect: EXTERNAL PROCEDURE;
FreeCmd: EXTERNAL PROCEDURE[CmdPtr];
Listen: EXTERNAL PROCEDURE;
NextCmd: EXTERNAL PROCEDURE RETURNS[pCmd: CmdPtr];
Refresh: EXTERNAL PROCEDURE;
RequestControl: EXTERNAL PROCEDURE RETURNS[BOOLEAN];
SendCmd: EXTERNAL PROCEDURE[pCmd: CmdPtr];
Yield: EXTERNAL PROCEDURE;

-- Global Variables --
boxShade: GrayTone ← 2;
centext: BOOLEAN ← TRUE; -- center text
pictureChanged: BOOLEAN ← FALSE; -- picture changed since last output
rebuildNeeded: BOOLEAN ← FALSE; -- display might have "holes"
etherOn: BOOLEAN ← FALSE;
textFont: FontNumber ← 0;
lineWidth: CARDINAL ← 2;
new, old: Coord; -- Cursor coordinates
tickon: BOOLEAN ← TRUE;

IsLetter: PROCEDURE[ch: CHARACTER] RETURNS[BOOLEAN]=
BEGIN RETURN[ch IN [’a..’z] OR ch IN [’A..’Z]] END;

UpperCase: PROCEDURE[ch: CHARACTER] RETURNS[CHARACTER]=
BEGIN
RETURN[IF ch IN [’a..’z]
THEN LOOPHOLE[InlineDefs.BITAND[LOOPHOLE[ch], 337B]] ELSE ch]
END;

------------------------------------------------------------------
-- STORAGE ALLOCATION
-- defines Rover, AllocateObject, FreeObject
rover: ObjPtr ← NIL; -- Pointer to current object in the circular list

Rover: PUBLIC PROCEDURE RETURNS[POINTER TO ObjPtr]=
BEGIN RETURN[@rover] END;

AllocateObject: PUBLIC PROCEDURE[kind: ObjKind]=
BEGIN
previous: ObjPtr ← rover;
rover ← SystemDefs.AllocateHeapNode[
SELECT kind FROM
line => SIZE[line Object],
area => SIZE[area Object],
text => SIZE[text Object],
ENDCASE => SIZE[Object]];
SELECT kind FROM
line => rover↑ ← Object[next: rover, zone:, state: dead, body: line[]];
area => rover↑ ← Object[next: rover, zone:, state: dead, body: area[]];
text => rover↑ ← Object[next: rover, zone:, state: dead, body: text[,]];
ENDCASE;
IF previous#NIL THEN
BEGIN rover.next←previous.next; previous.next ← rover END;
pictureChanged ← TRUE
END;

FreeObject: PUBLIC PROCEDURE[pObj: ObjPtr]=
BEGIN
WITH pObj SELECT FROM text =>
SystemDefs.FreeHeapString[str];
ENDCASE;
SystemDefs.FreeHeapNode[pObj];
pictureChanged ← TRUE
END;

------------------------------------------------------------------
MakeObject: PROCEDURE[kind: ObjKind, z: Zone]=
BEGIN
AllocateObject[kind];
rover.state ← selected; rover.zone ← z
END;

Display: PROCEDURE[pObj: ObjPtr]=
BEGIN z: Zone ← pObj.zone;
SELECT pObj.state FROM
dead => BEGIN EraseRectangle[z]; rebuildNeeded ← TRUE END;
active =>
WITH pObj SELECT FROM
line => PaintRectangle[12, z, black];
area => PaintRectangle[13, z, shade];
text => [] ← PaintString[str, z, fontno];
ENDCASE;
selected =>
WITH pObj SELECT FROM
line => PaintRectangle[12, z, gray];
area => PaintRectangle[13, z, shade];
text =>
BEGIN [] ← PaintString[str, z, fontno];
PaintRectangle[13, z, 1]
END;
ENDCASE;
ENDCASE
END;

MakeLine: PROCEDURE=
BEGIN -- draw line from old to new
w: INTEGER ← old.x - new.x;
h: INTEGER ← old.y - new.y;
IF ABS[w]<ABS[h] THEN
BEGIN -- line is vertical
w ← lineWidth; new.x ← old.x;
IF h<0 THEN -- top down
MakeObject[line, [old,w,-h]]
ELSE -- bottom up
MakeObject[line, [[new.x, new.y+lineWidth],w,h]];
new.x ← old.x
END ELSE
BEGIN -- line is horizontal
h ← lineWidth; new.y ← old.y;
IF w<0 THEN -- left to right
MakeObject[line, [old,-w,h]]
ELSE -- right to left
MakeObject[line, [[new.x+lineWidth, new.y],w,h]];
new.y ← old.y
END;
Display[rover];
SetMousePosition[new] -- indicate where we assumed the cursor to be
END;

MakeArea: PROCEDURE=
BEGIN
MakeObject[area, [[MIN[old.x, new.x], MIN[old.y, new.y]],
ABS[new.x-old.x], ABS[new.y-old.y]]];
WITH rover SELECT FROM area => shade ← boxShade; ENDCASE;
Display[rover]
END;

MakeText: PROCEDURE[ch: CHARACTER]=
BEGIN -- First character already in ch
i, w, h: CARDINAL;
header: STRING ← [80]; -- buffer for text input
pos: Coord;
s: STRING;
[w,h] ← GetString[header, textFont, ch]; rebuildNeeded ← TRUE;
IF w > 0 THEN
BEGIN ClearSelections;
s ← AllocateHeapString[header.length];
StringDefs.AppendString[s,header];
pos ← CursorPosition[];
IF centext THEN pos ← [pos.x - w/2, pos.y - h/2];
MakeObject[text, Zone[pos, w, h]];
WITH rover SELECT FROM text =>
BEGIN fontno ← textFont; str ← s; END;
ENDCASE;
Display[rover]
END
END;

MakeBox: PROCEDURE=
BEGIN
x0: CARDINAL ← MIN[old.x, new.x];
y0: CARDINAL ← MIN[old.y, new.y];
x1: CARDINAL ← MAX[old.x, new.x];
y1: CARDINAL ← MAX[old.y, new.y];
MakeObject[line, [[x0,y0], x1-x0, lineWidth]];
Display[rover];
MakeObject[line, [[x1,y0], lineWidth, y1-y0]];
Display[rover];
MakeObject[line, [[x0+lineWidth,y1], x1-x0, lineWidth]];
Display[rover];
MakeObject[line, [[x0,y0+lineWidth], lineWidth, y1-y0]];
Display[rover];
END;

ClearSelections: PROCEDURE=
BEGIN stop: ObjPtr ← rover;
IF rover#NIL THEN DO
IF rover.state=selected THEN
BEGIN
WITH rover SELECT FROM text =>
BEGIN state ← dead; Display[rover] END;
ENDCASE;
rover.state ← active; Display[rover]
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP
END;

NewPicture: PUBLIC PROCEDURE=
BEGIN
-- This routine relies on somebody else clearing the display
stop: ObjPtr ← rover; nextObj: ObjPtr;
IF rover#NIL THEN DO
nextObj ← rover.next;
FreeObject[rover];
IF (rover ← nextObj)=stop THEN BEGIN rover ← NIL; EXIT END
ENDLOOP;
rebuildNeeded ← TRUE
END;

AddPicture: PROCEDURE=
BEGIN
pictureChanged ← TRUE;
rebuildNeeded ← TRUE
END;

SelectObject: PROCEDURE= -- the one at the cursor’s position
BEGIN stop: ObjPtr ← rover;
selObj: ObjPtr ← NIL;
z: Zone;
p: CARDINAL ← maxCARDINAL; -- perimeter
x: INTEGER ← new.x;
y: INTEGER ← new.y;
IF rover#NIL THEN DO
IF rover.state=active THEN
BEGIN z ← rover.zone;
IF (x IN [z.point.x .. z.point.x+LOOPHOLE[z.w,INTEGER]]) AND
(y IN [z.point.y .. z.point.y+LOOPHOLE[z.h,INTEGER]]) AND
(z.w+z.h<p)
THEN BEGIN p ← z.w+z.h; selObj ← rover END
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
IF selObj#NIL THEN BEGIN selObj.state ← selected; Display[selObj] END
END;

SelectZone: PROCEDURE=
BEGIN stop: ObjPtr ← rover;
x0: INTEGER ← MIN[old.x, new.x];
y0: INTEGER ← MIN[old.y, new.y];
x1: INTEGER ← MAX[old.x, new.x];
y1: INTEGER ← MAX[old.y, new.y];
z: Zone;
IF rover#NIL THEN DO
IF rover.state=active THEN
BEGIN z ← rover.zone;
IF (z.point.x IN [x0..x1])
AND (z.point.x+LOOPHOLE[z.w,INTEGER] IN [x0..x1])
AND (z.point.y IN [y0..y1])
AND (z.point.y+LOOPHOLE[z.h,INTEGER] IN [y0..y1])
THEN BEGIN rover.state ← selected; Display[rover] END
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP
END;

SelectEverything: PROCEDURE=
BEGIN stop: ObjPtr ← rover;
IF rover#NIL THEN DO
IF rover.state=active THEN
BEGIN rover.state ← selected; Display[rover] END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP
END;

MoveSelectedObjects: PROCEDURE=
BEGIN stop: ObjPtr ← rover;
dx: INTEGER ← new.x - old.x;
dy: INTEGER ← new.y - old.y;
IF rover#NIL THEN DO
IF rover.state=selected THEN
BEGIN rover.state ← dead; Display[rover];
rover.zone.point.x ← rover.zone.point.x+dx;
rover.zone.point.y ← rover.zone.point.y+dy;
rover.state ← selected; Display[rover];
pictureChanged ← TRUE
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP
END;

DeleteSelectedObjects: PROCEDURE=
BEGIN
stop: ObjPtr ← rover;
pObj: ObjPtr;
IF rover#NIL THEN DO
pObj ← rover.next;
IF pObj.state=selected THEN
BEGIN pObj.state ← dead; Display[pObj];
IF pObj=rover THEN rover ← NIL ELSE rover.next ← pObj.next;
FreeObject[pObj]
END
ELSE rover ← pObj;
IF pObj=stop THEN EXIT
ENDLOOP
END;

CopySelectedObjects: PROCEDURE=
BEGIN oldObj: ObjPtr; stop: ObjPtr ← rover;
dx: INTEGER ← new.x - old.x;
dy: INTEGER ← new.y - old.y;
z: Zone;
IF rover#NIL THEN DO
IF rover.state=selected THEN
BEGIN
WITH rover SELECT FROM text =>
BEGIN state ← dead; Display[rover] END;
ENDCASE;
rover.state ← marked
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP;
IF rover#NIL THEN DO
IF rover.state=marked THEN
BEGIN rover.state ← active; Display[rover];
z ← rover.zone;
z ← [[z.point.x + dx, z.point.y + dy], z.w, z.h];
oldObj ← rover;
WITH old: oldObj SELECT FROM
line => MakeObject[line, z];
area =>
BEGIN
MakeObject[area, z];
WITH new: rover SELECT FROM
area => new.shade ← old.shade;
ENDCASE;
END;
text =>
BEGIN
MakeObject[text, z];
WITH new: rover SELECT FROM text =>
BEGIN new.fontno ← old.fontno;
new.str ← AllocateHeapString[old.str.length];
StringDefs.AppendString[new.str, old.str]
END;
ENDCASE;
END;
ENDCASE;
Display[rover]
END;
IF (rover ← rover.next)=stop THEN EXIT
ENDLOOP
END;

Rebuild: PUBLIC PROCEDURE=
BEGIN
counter: CARDINAL ← 0;
stop: ObjPtr ← rover;
oldIcon: CursorIcon ← SetCursorIcon[rebuild];
IF rover#NIL THEN DO
Display[rover];
IF (rover ← rover.next)=stop OR (counter ← counter+1)=rebuildChunk THEN
BEGIN
IF MouseValue[]#0 OR NOT keys.endof[keys] THEN GOTO interrupt;
IF etherOn THEN
BEGIN
Yield; -- let Pup Package do its thing
IF CmdWaiting[] THEN GOTO interrupt
END;
IF rover=stop THEN EXIT;
counter ← 0
END
REPEAT
interrupt =>
BEGIN
[] ← SetCursorIcon[oldIcon];
rebuildNeeded ← TRUE;
RETURN
END
ENDLOOP;
IF tickon THEN DisplayTicks;
rebuildNeeded ← FALSE;
[] ← SetCursorIcon[oldIcon]
END;

Ticks: PROCEDURE[newTick: BOOLEAN]=
BEGIN
IF newTick#tickon THEN
BEGIN
tickon ← newTick;
IF tickon THEN DisplayTicks
ELSE BEGIN EraseTicks; rebuildNeeded ← TRUE END
END
END;

NextDigit: PROCEDURE [prompt: STRING, max: CARDINAL] RETURNS [CARDINAL]=
BEGIN d: CARDINAL; ch: CHARACTER;
headOrg: Coord= [32,16]; -- origin for text display
strHeight: CARDINAL ← FontHeight[fontno: 0];
strWidth: CARDINAL ← PaintString[prompt, [point: headOrg, w: BMBitsPerLine-headOrg.x, h: strHeight], 0];
ch ← ReadChar[];
EraseRectangle[[point: headOrg, w: strWidth, h: strHeight]];
rebuildNeeded ← TRUE;
d ← LOOPHOLE[ch, CARDINAL] - 60B;
IF d IN [0..max] THEN RETURN [d] ELSE RETURN [0]
END;

MouseAction: PROCEDURE[mouseEvent: CARDINAL]=
BEGIN
SetMousePosition[new]; -- indicate mouseposition at entry to command
SELECT mouseEvent FROM
0=> -- Blue button -- -- select
BEGIN ClearSelections;
IF ABS[new.x-old.x]+ABS[new.y-old.y]>16 THEN SelectZone ELSE SelectObject
END;
1=> -- Blue button + LeftShift key -- -- multiple select
IF ABS[new.x-old.x]+ABS[new.y-old.y]>16 THEN SelectZone ELSE SelectObject;
2=> -- Blue button + Ctrl key -- NULL;
3=> -- Blue button + LeftShift + Ctrl keys -- NULL;
4=> -- Yellow button -- -- draw line
BEGIN ClearSelections;
IF new#old THEN MakeLine;
END;
5=> -- Yellow button + LeftShift key -- -- draw box
BEGIN ClearSelections;
IF new#old THEN MakeBox;
END;
6=> -- Yellow button + Ctrl key -- -- draw area
BEGIN ClearSelections;
IF new#old THEN MakeArea;
END;
7=> -- Yellow button + LeftShift + Ctrl keys -- NULL;
8=> -- Red button -- -- move
IF new#old THEN MoveSelectedObjects;
9=> -- Red button + LeftShift key -- -- copy
IF new#old THEN CopySelectedObjects;
10=> -- Red button + Ctrl key -- NULL;
11=> -- Red button + LeftShift + Ctrl keys -- NULL;
ENDCASE;
END;

MouseCmd: PROCEDURE[mouseEvent: CARDINAL]=
BEGIN cmd: CmdObj;
MouseAction[mouseEvent];
IF etherOn THEN
BEGIN
cmd ← [mouse[mouseEvent,old,new]];
SendCmd[@cmd]
END;
END;

KeyAction: PROCEDURE RETURNS[{goOn, quit}]=
BEGIN
ch: CHARACTER ← ReadChar[];
[] ← SetCursorIcon[input];
IF ch=DEL THEN BEGIN DeleteSelectedObjects; KeyCmd[DEL,0] END
ELSE IF ch>’ THEN StringCmd[ch]
ELSE
SELECT ch FROM
ControlA=> -- ↑Add file
BEGIN TypeScriptWindow;
WriteString["Add "];
IF (IF pictureChanged THEN Confirm[] ELSE TRUE) THEN
BEGIN AddPicture; Input;
IF etherOn THEN Refresh
END;
BitMapDisplay
END;
ControlC=> -- set ↑Color
BEGIN
boxShade ← NextDigit["Color", black];
KeyCmd[ControlC,boxShade];
END;
ControlD=> -- ↑Debug
SIGNAL Debug;
ControlE=> -- ↑Ethernet action
BEGIN TypeScriptWindow;
WriteString["EtherNet command: Listen/Connect/Refresh/Disconnect: "];
SELECT UpperCase[ReadChar[]] FROM
’L => -- Listen
BEGIN WriteLine["Listen"];
IF etherOn THEN Error["Already listening"] ELSE Listen
END;
’C => -- Connect
BEGIN WriteLine["Connect"];
IF etherOn THEN Error["Disconnect first"] ELSE Connect
END;
’R => -- Refresh
BEGIN WriteLine["Refresh"];
IF NOT etherOn THEN Error["No connections"]
ELSE Refresh
END;
’D => -- Disconnect
BEGIN WriteLine["Disconnect"];
IF NOT etherOn THEN Error["No connections"] ELSE Disconnect
END;
ENDCASE => WriteLine["XXX"];
BitMapDisplay
END;
ControlF=> -- set ↑Font number
BEGIN
textFont ← NextDigit["Font number", LAST[FontNumber]];
IF NOT FontLoaded[textFont] THEN textFont ← 0;
KeyCmd[ControlF,textFont]
END;
ControlG=> -- set ↑Grid spacing
BEGIN
SetGridSpacing[gridSpacing ← NextDigit["Gridspacing", LAST[GridSpacing]]];
KeyCmd[ControlG, gridSpacing];
END;
ControlH=> -- ↑Hardcopy
BEGIN TypeScriptWindow;
WriteLine["Hardcopy"]; HardCopy;
BitMapDisplay
END;
ControlI=> -- ↑Input file
BEGIN TypeScriptWindow;
WriteString["Input "];
IF (IF pictureChanged THEN Confirm[] ELSE TRUE) THEN
BEGIN NewPicture; Input;
IF etherOn THEN Refresh
END;
BitMapDisplay
END;
ControlO=> -- ↑Output
BEGIN TypeScriptWindow;
WriteLine["Output"]; Output;
pictureChanged ← FALSE;
BitMapDisplay
END;
ControlQ=> -- ↑Quit
BEGIN TypeScriptWindow;
WriteString["Quit "];
IF (IF pictureChanged THEN Confirm[] ELSE TRUE) THEN
BEGIN
IF etherOn THEN Disconnect;
RETURN[quit]
END;
BitMapDisplay
END;
ControlR=> -- ↑Restart
BEGIN TypeScriptWindow;
WriteString["Restart "];
IF (IF pictureChanged THEN Confirm[] ELSE TRUE) THEN
BEGIN
NewPicture;
ChangeFonts;
KeyCmd[ControlR,0]
END;
BitMapDisplay
END;
ControlS=> -- ↑Shrink bitmap
BEGIN
ShrinkBM;
KeyCmd[ControlS,0]
END;
ControlT=> -- on/off ↑Ticks
BEGIN
Ticks[NOT tickon];
KeyCmd[ControlT,tickon]
END;
ControlW=> -- set line↑Width
BEGIN
lineWidth ← NextDigit["line Width", 9];
IF lineWidth=0 THEN lineWidth ← 16;
KeyCmd[ControlW,lineWidth];
END;
ControlX=> -- centered/not centered te↑Xt
BEGIN
centext ← NOT centext;
KeyCmd[ControlX,centext]
END;
ControlY=> -- select ever↑Ything
BEGIN
SelectEverything;
KeyCmd[ControlY,0]
END;
ENDCASE;
[] ← SetCursorIcon[arrow];
RETURN[goOn]
END;

KeyCmd: PROCEDURE[ch: CHARACTER, word: UNSPECIFIED]=
BEGIN cmd: CmdObj;
IF etherOn THEN BEGIN
cmd ← [keyboard[ch,word]];
SendCmd[@cmd]
END
END;

StringCmd: PROCEDURE[ch: CHARACTER]=
BEGIN cmd: CmdObj; tmp: STRING;
MakeText[ch];
IF etherOn THEN BEGIN
WITH rover SELECT FROM text =>
BEGIN
tmp ← AllocateHeapString[str.length];
StringDefs.AppendString[tmp, str];
cmd ← [text[zone, tmp]];
SendCmd[@cmd]
END;
ENDCASE;
END
END;

MarkCmd: PROCEDURE[point: Coord, icon: CursorIcon]=
BEGIN cmd: CmdObj;
Mark[point, icon];
IF etherOn THEN BEGIN
cmd ← [mark[point, icon]];
SendCmd[@cmd]
END
END;

CursorCmd: PROCEDURE[point: Coord]=
BEGIN cmd: CmdObj;
IF etherOn THEN BEGIN
cmd ← [cursor[point]];
SendCmd[@cmd]
END
END;

SetCursorIconCmd: PROCEDURE[icon: CursorIcon] RETURNS[oldIcon: CursorIcon]=
BEGIN cmd: CmdObj;
oldIcon ← SetCursorIcon[icon];
IF etherOn THEN BEGIN
cmd ← [setCursorIcon[icon]];
SendCmd[@cmd]
END
END;

InputStatus: PUBLIC PROCEDURE[GetWord: PROCEDURE RETURNS[WORD]]=
BEGIN
boxShade ← GetWord[];
textFont ← GetWord[];
SetGridSpacing[gridSpacing ← GetWord[]];
Ticks[LOOPHOLE[GetWord[]]];
lineWidth ← GetWord[];
centext ← LOOPHOLE[GetWord[]]
END;

OutputStatus: PUBLIC PROCEDURE[PutWord: PROCEDURE[word: WORD]]=
BEGIN
PutWord[boxShade];
PutWord[textFont];
PutWord[gridSpacing];
PutWord[LOOPHOLE[tickon]];
PutWord[lineWidth];
PutWord[LOOPHOLE[centext]]
END;

ZoneChecking: PROCEDURE RETURNS[BOOLEAN]=
BEGIN
z: FSPDefs.ZonePointer ← SystemDefs.HeapZone[];
RETURN[z.checking ← NOT z.checking]
END;

SetEtherOn: PUBLIC PROCEDURE[newValue: BOOLEAN]=
BEGIN etherOn ← newValue END;

--------------------------------------------------------------------
-- Used at the end of the main program only
StopMesa: EXTERNAL PROCEDURE;
--------------------------------------------------------------------
-- MAIN PROGRAM
keys: StreamHandle;
mouseValue, mouseEvent: CARDINAL; -- mouse buttons
pCmd: CmdPtr;
gridSpacing: GridSpacing;
tmp: Coord;
Debug: SIGNAL= CODE; -- Used to get to the debugger

[] ← SetCursorIcon[arrow];
SetGridSpacing[gridSpacing ← 3];
keys ← GetDefaultKey[];
IF zoneChecking THEN [] ← ZoneChecking[];
InitDisplay;

--------------------------------------------------------------------
-- Surround the following loop with this enable-clause in TeleSilResident
-- ENABLE SegmentDefs.InsufficientVM => BEGIN ShrinkBM; RESUME END;
--------------------------------------------------------------------

DO
IF (mouseValue ← MouseValue[])#0 AND RequestControl[] THEN
BEGIN -- Mouse Action!
new ← old ← CursorPosition[];
mouseEvent ← MouseEvent[mouseValue];
CursorCmd[tmp ← old];
IF mouseEvent=2 THEN [] ← SetCursorIconCmd[blackArrow]
ELSE MarkCmd[old, greyArrow];
WHILE MouseValue[]#0 DO -- Mouse button down
IF etherOn THEN Yield; -- Let Pup Package do its thing
new ← CursorPosition[];
IF new#tmp THEN CursorCmd[tmp ← new]
ENDLOOP;
IF mouseEvent=2 THEN [] ← SetCursorIconCmd[arrow]
ELSE BEGIN MarkCmd[old, greyArrow]; MouseCmd[MouseEvent[mouseValue]] END
END;

IF NOT keys.endof[keys] AND RequestControl[] THEN -- Keyboard Action!
IF KeyAction[]=quit THEN EXIT;

IF etherOn THEN
BEGIN
Yield; -- Let PUP Package do its thing

WHILE CmdWaiting[] DO
pCmd ← NextCmd[];
IF pCmd#NIL THEN
BEGIN
WITH pCmd SELECT FROM
mouse =>
BEGIN old ← oldCoord; new ← newCoord;
MouseAction[mouseEvent]
END;
keyboard =>
SELECT char FROM
DEL => DeleteSelectedObjects;
ControlC => boxShade ← info;
ControlF => textFont ← info;
ControlG => SetGridSpacing[gridSpacing ← info];
ControlR =>
BEGIN TypeScriptWindow;
Error["Restart not implemented"];
BitMapDisplay
END;
ControlS => ShrinkBM;
ControlT => Ticks[info];
ControlW => lineWidth ← info;
ControlX => centext ← info;
ControlY => SelectEverything;
ENDCASE;
text =>
BEGIN MakeObject[text, z];
WITH rover SELECT FROM text =>
BEGIN fontno ← textFont; str ← s END;
ENDCASE;
Display[rover]
END;
ENDCASE;
FreeCmd[pCmd];
Yield; -- Let PUP Package do its thing - again
END
ENDLOOP
END;

IF rebuildNeeded THEN Rebuild
ENDLOOP;

StopMesa
END.