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: BOOLEANFALSE;
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: BOOLFALSE] = 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.