<> <> <> <> <> 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]}; <> 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.