CDDrawImpl.mesa (part of Chipndale)
by Christian Jacobi July 6, 1983 5:09 pm
last edited Christian Jacobi September 7, 1983 9:43 am
DIRECTORY
TerminalIO,
CD USING [DesignRect, Rect, Design],
CDInline,
CDDraw;
CDDrawImpl: CEDAR MONITOR
IMPORTS CDInline, TerminalIO
EXPORTS CDDraw =
BEGIN
CommandTable: TYPE = REF CTableRep;
CommType: TYPE = CDDraw.CommType;
Comm: TYPE = CDDraw.Comm;
maxC: CARDINAL = 50;
CTableRep: PUBLIC TYPE = RECORD [
cnt, in, out: CARDINAL,
commandAvail: CONDITION,
desgn: CD.Design,
deviceClip: CD.DesignRect,
comm: ARRAY [0..maxC) OF Comm,
stopFlag: REF BOOLEAN, -- must be monitored
-- request to stop the execution of (only!) the current command
inlist: BOOLEANFALSE,
deleted: BOOLEANFALSE,
alldoneToBeReported: BOOLEANFALSE
];
TableList: TYPE = LIST OF CommandTable;
tableList: TableList←NIL;
InsertList: INTERNAL PROC [ct: CommandTable] =
BEGIN
IF NOT ct.inlist THEN {
tableList ← CONS[ct, tableList];
ct.inlist ← TRUE;
};
END;
RemoveList: INTERNAL PROC [ct: CommandTable] =
BEGIN
IF ct.inlist THEN {
ct.inlist ← FALSE;
-- tableList#NIL; otherwise nothing too delete! not ct.inlist
IF tableList.first=ct THEN tableList ← tableList.rest
ELSE
FOR l: TableList ← tableList, l.rest WHILE l.rest#NIL DO
IF l.rest.first=ct THEN
{l.rest ← l.rest.rest; EXIT}
ENDLOOP
};
END;
CreateCommandTable: PUBLIC ENTRY PROC [design: CD.Design, clip: CD.DesignRect, cleanStopFlag: REF BOOLEAN] RETURNS [CommandTable] =
--cleanStopFlag^ tells any drawing process to stop volunterly and to fetch the next
--command.
--cleanStopFlag^ must not be modified any more outside this monitor!!
--until DeleteCommandTable is called
--Users may request a stop by calling FlushCommands.
BEGIN
ct: CommandTable ~ NEW[CTableRep];
TerminalIO.WriteRope["Create a viewer\n"];
ct.cnt ← ct.in ← ct.out ← 0;
ct.deviceClip ← clip;
ct.desgn ← design;
ct.deleted ← ct.inlist ← ct.alldoneToBeReported ← FALSE;
ct.stopFlag ← cleanStopFlag; -- assigns addresses
ct.stopFlag^ ← FALSE;
InsertList[ct];
RETURN [ct]
END;
ModifyCommandTable: PUBLIC ENTRY PROC [design: CD.Design, ct: CommandTable, clip: CD.DesignRect] =
--changes the clipping aera
BEGIN
InternalFlush[ct];
ct.deviceClip ← clip;
ct.desgn ← design;
IF CDInline.NonEmpty[clip] THEN InsertList[ct]
ELSE RemoveList[ct]
END;
DestroyCommandTable: PUBLIC ENTRY PROC [ct: CommandTable] =
--no more calls of InsertCommand on ct allowed!!
--draw process must disapear from itself,
--when draw process dispears and contains nomore
--reference of ct, it is subject for garbage collection
--The cleanStopFlag is immediately set to TRUE and later
--reset to FALSE when the draw
--process stopped the current command, if it then fetches another
--command it gets the disapearforever command.
BEGIN
ct.deleted ← TRUE;
InternalFlush[ct];
RemoveList[ct];
ct.desgn ← NIL;
END;
InsertCommand: PUBLIC ENTRY PROC [ct: CommandTable, c: Comm] =
BEGIN
IF ct.inlist THEN InternalInsertCommand[ct, c]
END;
InternalInsertCommand: INTERNAL PROC [ct: CommandTable, c: Comm] =
--this procedure introduces redraw all if table is full
--and in removes certain rectangles contained by others
--this implies that the module knows the commands
BEGIN
IF (ct.cnt>=maxC) OR (c.cmd=all) THEN
{c ← Comm[cmd: all, erase: TRUE, rect: ct.deviceClip]; InternalFlush[ct]};
IF ct.deleted THEN ERROR; -- at least until it is known
IF c.cmd=disapearforever THEN ERROR; -- at least until it is known
IF c.cmd=alldone THEN ERROR; -- at least until it is known
ct.alldoneToBeReported ← TRUE;
IF (ct.cnt=1) AND (ct.comm[ct.out].cmd=all) THEN RETURN;
IF c.cmd=rect THEN {
IF CDInline.Intersect[c.rect, ct.deviceClip] THEN {
j: CARDINAL ← ct.out;
c.rect ← CDInline.Intersection[c.rect, ct.deviceClip];
--this search for similar commands could be made much better
THROUGH [0..ct.cnt) DO
IF ct.comm[j].cmd=rect THEN {
IF CDInline.Inside[c.rect, ct.comm[j].rect] THEN
{ct.comm[j].erase ← ct.comm[j].erase OR c.erase; RETURN};
IF CDInline.Inside[ct.comm[j].rect, c.rect] THEN
{ct.comm[j].erase ← ct.comm[j].erase OR c.erase;
ct.comm[j].rect ← c.rect; RETURN};
};
j ← (j+1) MOD maxC;
ENDLOOP
}
ELSE RETURN;
};
ct.cnt ← ct.cnt+1;
ct.comm[ct.in] ← c;
ct.in ← (ct.in+1) MOD maxC;
NOTIFY ct.commandAvail;
END;
InsertCommandAll: PUBLIC ENTRY PROC [design: CD.Design, c: Comm] =
BEGIN
FOR lst: TableList ← tableList, lst.rest WHILE lst#NIL DO
IF lst.first.desgn=design THEN InternalInsertCommand[lst.first, c];
ENDLOOP
END;
FetchCommand: PUBLIC ENTRY PROC [ct: CommandTable] RETURNS [c: Comm] =
--waits till command is available or CommandTable deleted
BEGIN
ct.stopFlag^ ← FALSE;
WHILE ct.cnt<=0 DO
IF ct.deleted THEN InsertDisappear[ct]
ELSE
IF ct.alldoneToBeReported THEN InsertAlldone[ct]
ELSE WAIT ct.commandAvail;
ct.stopFlag^ ← FALSE;
ENDLOOP;
ct.cnt ← ct.cnt-1;
c ← ct.comm[ct.out];
ct.out ← (ct.out+1) MOD maxC;
END;
FlushCommands: PUBLIC ENTRY PROC [ct: CommandTable]=
-- the drawing may stop after some time only,
-- and NOT immediately with procedure return
BEGIN
InternalFlush[ct]
END;
InternalFlush: INTERNAL PROC [ct: CommandTable] =
BEGIN
ct.cnt ← ct.in ← ct.out ← 0;
ct.stopFlag^ ← TRUE;
ct.alldoneToBeReported ← FALSE;
NOTIFY ct.commandAvail;
END;
InsertDisappear: INTERNAL PROC [ct: CommandTable] =
BEGIN
ct.out ← 0;
ct.cnt ← 1;
ct.comm[0] ← Comm[cmd: disapearforever, erase: FALSE, rect: [1,1,0,0]];
ct.in ← (1 MOD maxC);
END;
InsertAlldone: INTERNAL PROC [ct: CommandTable] =
BEGIN
ct.alldoneToBeReported ← FALSE;
ct.out ← 0;
ct.cnt ← 1;
ct.comm[0] ← Comm[cmd: alldone, erase: FALSE, rect: [1,1,0,0]];
ct.in ← (1 MOD maxC);
END;
END.