CaretsImpl.mesa; Edited by McGregor on May 31, 1983 11:18 am
Last Edited by: Maxwell, May 19, 1983 1:24 pm
DIRECTORY
Carets,
ColorWorld USING [NewContext],
Graphics USING [Context, NewContext, SetCP, SetPaintMode],
GraphicsOps USING [BitmapRef, BitmapRep, DrawBitmap],
Process USING [Detach, MsecToTicks, SetTimeout],
ViewerClasses USING [Viewer],
ViewerOps USING [UserToScreenCoords];
CaretsImpl: CEDAR MONITOR
IMPORTS ColorWorld, Graphics, GraphicsOps, Process, ViewerOps
EXPORTS Carets =
BEGIN OPEN Carets;
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
IF x =-10000 AND y =-10000 THEN SELECT id FROM -- special reset for ViewerBLTImpl to move viewers
primary => {x ← pViewerX; y ← pViewerY};
secondary => {x ← sViewerX; y ← sViewerY};
ENDCASE;
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;
InvertCaret: INTERNAL PROC [id: CaretId, kill: BOOLFALSE] = BEGIN
context: Graphics.Context ← screen;
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;
Graphics.SetCP[context, pCaretX-caretXOffset, pCaretY];
GraphicsOps.DrawBitmap[context, pCaret, 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;
Graphics.SetCP[context, sCaretX-caretXOffset, sCaretY];
GraphicsOps.DrawBitmap[context, sCaret, 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 ← ColorWorld.NewContext[];
[] ← Graphics.SetPaintMode[colorScreen, invert];
END;
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: Graphics.Context ← Graphics.NewContext[];
colorScreen: Graphics.Context;
pCaret: GraphicsOps.BitmapRef ← NEW[GraphicsOps.BitmapRep ← [base: NEW[CaretArray ← [
000400B,
001600B,
003700B,
003300B,
006140B,
004040B
]],
raster: (caretW+15)/16,
width: caretW,
height: caretH
]];
sCaret: GraphicsOps.BitmapRef ← NEW[GraphicsOps.BitmapRep ← [base: NEW[CaretArray ← [
000400B,
001200B,
002100B,
002100B,
004040B,
004040B
]],
raster: (caretW+15)/16,
width: caretW,
height: caretH
]];
[] ← Graphics.SetPaintMode[screen, invert];
TRUSTED {Process.Detach[FORK CaretProcess]}; -- start the blinker
END.