CaretsImpl.mesa; Written by S. McGregor
Edited by McGregor on August 4, 1983 12:53 pm
Last Edited by: Maxwell, May 19, 1983 1:24 pm
Michael Plass, August 16, 1983 9:12 am
Doug Wyatt, October 25, 1983 5:38 pm
DIRECTORY
Carets USING [CaretId],
Imager USING [Context, Create, MaskBits, SetColor, XOR],
Process USING [Detach, MsecToTicks, SetTimeout],
ViewerClasses USING [Viewer],
ViewerOps USING [UserToScreenCoords];
CaretsImpl: CEDAR MONITOR
IMPORTS Imager, Process, ViewerOps
EXPORTS Carets
= BEGIN
CaretId: TYPE = Carets.CaretId;
timeOut: CONDITION;
caretH: INTEGER = 6;
caretW: INTEGER = 16;
caretXOffset: CARDINAL = 8;
CaretArray: TYPE = ARRAY [0..caretH) OF UNSPECIFIED;
pCaretX, pCaretY, sCaretX, sCaretY: INTEGER;
pViewerX, pViewerY, sViewerX, sViewerY: INTEGER;
pDark, sDark: BOOLEAN ← FALSE;
pCaretViewer, sCaretViewer: PUBLIC ViewerClasses.Viewer;
screen: Imager.Context ← Imager.Create[$LFDisplay];
colorScreen: Imager.Context;
pCaret: CaretArray ← [
000400B,
001600B,
003700B,
003300B,
006140B,
004040B
];
sCaret: CaretArray ← [
000400B,
001200B,
002100B,
002100B,
004040B,
004040B
];
StartCaret:
PUBLIC
ENTRY
PROC [viewer: ViewerClasses.Viewer, x, y:
INTEGER, id: CaretId] =
BEGIN
ENABLE UNWIND => NULL;
IF viewer = NIL THEN RETURN;
InvertCaret[id, TRUE]; -- kill off old visible caret
x ← MIN[x, viewer.cw];
IF id=primary
THEN {
pViewerX ← x; pViewerY ← y;
[pCaretX, pCaretY] ←ViewerOps.UserToScreenCoords[pCaretViewer ← viewer, x, y]}
ELSE {
sViewerX ← x; sViewerY ← y;
[sCaretX, sCaretY] ← ViewerOps.UserToScreenCoords[sCaretViewer ← viewer, x, y]};
Screw the NOTIFY; CaretProcess will eventually wake up and notice new caret
END;
StopCaret:
PUBLIC
ENTRY
PROC [id: CaretId] =
BEGIN
ENABLE UNWIND => NULL;
InvertCaret[id, TRUE];
END;
caretHoldCount: INTEGER ← 0; -- number of requests pending to suspend caret
SuspendCarets:
PUBLIC
ENTRY
PROC =
BEGIN
ENABLE UNWIND => NULL;
IF pDark AND pCaretViewer#NIL THEN InvertCaret[primary];
IF sDark AND sCaretViewer#NIL THEN InvertCaret[secondary];
caretHoldCount ← caretHoldCount+1;
END;
ResumeCarets:
PUBLIC
ENTRY
PROC =
BEGIN
ENABLE UNWIND => NULL;
caretHoldCount ← MAX[0, caretHoldCount-1];
END;
ResetCarets:
PUBLIC
PROC = {
StartCaret[pCaretViewer, pViewerX, pViewerY, primary];
StartCaret[sCaretViewer, sViewerX, sViewerY, secondary];
}; -- special reset for ViewerBLTImpl to move viewers
InvertCaret:
INTERNAL
PROC [id: CaretId, kill:
BOOL ←
FALSE] =
BEGIN
context: Imager.Context ← screen;
IF pCaretY
IN [-caretH..16000)
THEN {
IF id=primary
THEN
BEGIN
IF (~kill
OR pDark)
AND pCaretViewer#
NIL
THEN
BEGIN
IF pCaretViewer.column=color
THEN
BEGIN
IF colorScreen=NIL THEN InitColorCaret;
context ← colorScreen;
END;
TRUSTED {Imager.MaskBits[context, @pCaret, 1, [pCaretX-caretXOffset,pCaretY-caretH,caretW,caretH], [pCaretX-caretXOffset,pCaretY-caretH,caretW,caretH]]};
pDark ← ~pDark;
END;
IF kill THEN pCaretViewer ← NIL;
END
ELSE
BEGIN
IF (~kill
OR sDark)
AND sCaretViewer#
NIL
THEN
BEGIN
IF sCaretViewer.column=color
THEN
BEGIN
IF colorScreen=NIL THEN InitColorCaret;
context ← colorScreen;
END;
TRUSTED {Imager.MaskBits[context, @sCaret, 1, [sCaretX-caretXOffset,sCaretY-caretH,caretW,caretH], [sCaretX-caretXOffset,sCaretY-caretH,caretW,caretH]]};
sDark ← ~sDark;
END;
IF kill THEN sCaretViewer ← NIL;
END;
};
END;
CaretProcess:
ENTRY
PROC =
BEGIN
ENABLE UNWIND => NULL;
TRUSTED {Process.SetTimeout[@timeOut, Process.MsecToTicks[500]]};
DO
WAIT timeOut;
IF caretHoldCount#0 THEN LOOP; -- suspended
IF pCaretViewer#NIL THEN InvertCaret[primary];
IF sCaretViewer#NIL THEN InvertCaret[secondary];
ENDLOOP;
END;
InitColorCaret:
PROC =
BEGIN
colorScreen ← Imager.Create[$ColorDisplay];
[] ← Imager.SetColor[colorScreen, Imager.XOR];
END;
[] ← Imager.SetColor[screen, Imager.XOR];
TRUSTED {Process.Detach[FORK CaretProcess]}; -- start the blinker
END.