CDDrawImpl.mesa (part of Chipndale)
Copyright © 1983, 1984 by Xerox Corporation. All rights reserved.
by Christian Jacobi July 6, 1983 5:09 pm
last edited Christian Jacobi November 5, 1984 10:18:44 am PST
DIRECTORY
CD USING [DesignRect, Rect, Design],
CDBasics,
CDDraw;
CDDrawImpl:
CEDAR
MONITOR
IMPORTS CDBasics
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: BOOLEAN ← FALSE,
deleted: BOOLEAN ← FALSE,
alldoneToBeReported: BOOLEAN ← FALSE
];
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
ENABLE UNWIND => NULL; --catches eg on cleanStopFlag=NIL
ct: CommandTable ~ NEW[CTableRep];
ct.cnt ← ct.in ← ct.out ← 0;
ct.deviceClip ← clip;
ct.desgn ← design;
ct.stopFlag ← cleanStopFlag; -- assigns addresses
ct.deleted ← ct.inlist ← ct.alldoneToBeReported ← 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
ENABLE UNWIND => NULL;
InternalFlush[ct];
ct.deviceClip ← clip;
ct.desgn ← design;
IF CDBasics.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
ENABLE UNWIND => NULL;
IF ct#
NIL
THEN {
ct.deleted ← TRUE;
InternalFlush[ct];
RemoveList[ct];
ct.desgn ← NIL;
}
END;
InsertCommand:
PUBLIC
ENTRY
PROC [ct: CommandTable, c: Comm] =
BEGIN
ENABLE UNWIND => NULL;
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 CDBasics.Intersect[c.rect, ct.deviceClip]
THEN {
j: CARDINAL ← ct.out;
c.rect ← CDBasics.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 CDBasics.Inside[c.rect, ct.comm[j].rect]
THEN
{ct.comm[j].erase ← ct.comm[j].erase OR c.erase; RETURN};
IF CDBasics.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
ENABLE UNWIND => NULL;
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
ENABLE UNWIND => NULL;
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
ENABLE UNWIND => NULL;
IF ct#NIL THEN 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.