DIRECTORY Process USING [Detach, MsecToTicks, SetTimeout, Ticks], Rope USING [Concat, Fetch, FromProc, Length, ROPE], TextEdit USING [InsertRope, InsertString], TextNode USING [NarrowToTextNode, Location, Ref], TEditDocument USING [Selection], TEditInput USING [currentEvent], TEditInputOps, TEditLocks USING [Lock, Unlock], TEditRefresh USING [ScrollToEndOfSel], TEditSelection USING [Alloc, Free, CaretVisible, Copy, InsertionPoint, LockSel, MakePointSelection, pSel, SelectionRoot, UnlockSel]; TEditBufferedInputImpl: CEDAR MONITOR IMPORTS Process, Rope, TextEdit, TextNode, TEditInput, TEditInputOps, TEditLocks, TEditRefresh, TEditSelection EXPORTS TEditInputOps SHARES TEditInputOps = BEGIN OPEN TEditSelection; repainting: BOOL _ FALSE; editRepaintProcess: PROCESS _ NIL; repaintDone: CONDITION; bufferMaxlen: CARDINAL _ 32; inputBuffer: REF TEXT _ NEW[TEXT[bufferMaxlen]]; inputRope: Rope.ROPE; aLittleWhile: Process.Ticks = Process.MsecToTicks[50]; untilTimesOutInALittleWhile: CONDITION; bufferClear: CONDITION; BufferedInsertChar: PUBLIC ENTRY PROC [char: CHAR] = { ENABLE UNWIND => NULL; -- release lock count: INTEGER _ 0; WHILE inputBuffer.length >= bufferMaxlen DO -- buffer full IF (count _ count+1) > 10 THEN { -- waited long enough i: CARDINAL _ 0; Char: PROC RETURNS [c: CHAR] = { c _ inputBuffer[i]; i _ i+1 }; rope: Rope.ROPE _ Rope.FromProc[inputBuffer.length, Char]; inputRope _ Rope.Concat[inputRope, rope]; inputBuffer.length _ 0; EXIT }; BROADCAST untilTimesOutInALittleWhile; -- wake up the repaint process WAIT bufferClear; -- this will time out if repaint fails to empty the buffer ENDLOOP; inputBuffer[inputBuffer.length] _ char; inputBuffer.length _ inputBuffer.length + 1; IF NOT repainting THEN { TRUSTED { Process.Detach[editRepaintProcess _ FORK Repaint[]] }; repainting _ TRUE; }; }; BufferedInsertText: PUBLIC PROC [text: Rope.ROPE] = { FOR n: LONG INTEGER IN [0..Rope.Length[text]) DO BufferedInsertChar[Rope.Fetch[text, n]]; ENDLOOP; }; WaitForInsertToFinish: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; -- release lock WHILE repainting DO WAIT repaintDone; ENDLOOP; }; NoteRepaintDone: ENTRY PROC = { editRepaintProcess _ NIL; repainting _ FALSE; BROADCAST repaintDone; }; Repaint: PROC = { root: TextNode.Ref; docLock: BOOL _ FALSE; tSel: TEditDocument.Selection; Cleanup: PROC = { TEditSelection.UnlockSel[primary]; IF docLock THEN TEditLocks.Unlock[root]; IF tSel # NIL THEN Free[tSel]; NoteRepaintDone[]; }; { ENABLE { UNWIND => Cleanup[]; ABORTED => GOTO Quit; }; DoInsertions: ENTRY PROC = { caretVisible: BOOL _ TEditSelection.CaretVisible[]; WHILE MakeEdits[root, tSel, caretVisible] DO IF inputRope=NIL AND inputBuffer.length Cleanup[]; }; }; MakeEdits: INTERNAL PROC [root: TextNode.Ref, tSel: TEditDocument.Selection, caretVisible: BOOL] RETURNS [BOOL] = { ENABLE UNWIND => NULL; pos: TextNode.Location _ InsertionPoint[pSel]; IF root=NIL OR pos.node=NIL OR (inputRope=NIL AND inputBuffer.length=0) THEN RETURN[FALSE]; Copy[source: pSel, dest: tSel]; [] _ TextEdit.InsertString[ root: root, dest: TextNode.NarrowToTextNode[pos.node], string: inputBuffer, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; IF inputRope#NIL THEN [] _ TextEdit.InsertRope[ root: root, dest: TextNode.NarrowToTextNode[pos.node], rope: inputRope, destLoc: pos.where, inherit: FALSE, looks: tSel.looks, event: TEditInput.currentEvent]; pos.where _ pos.where+inputBuffer.length+Rope.Length[inputRope]; TEditSelection.MakePointSelection[tSel, pos]; IF caretVisible THEN TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE]; inputBuffer.length _ 0; inputRope _ NIL; BROADCAST bufferClear; RETURN[TRUE]; }; TRUSTED { Process.SetTimeout[@untilTimesOutInALittleWhile, aLittleWhile]; Process.SetTimeout[@bufferClear, aLittleWhile]; }; END. ΌTEditBufferedInputImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) June 10, 1985 10:37:44 pm PDT Michael Plass, March 29, 1985 3:51:11 pm PST Doug Wyatt, June 22, 1985 1:03:47 pm PDT Get document and selection locks outside of monitor to avoid deadlock with someone doing an insert char while holding a lock. insert it in front of the inputBuffer string after repaint finishes, do an autoscroll Κβ˜codešœ™Kšœ Οmœ1™Kšœ žœ˜Kšœ˜Kšžœžœ˜ Kšžœ˜Kšœ˜—Kšœ˜K˜—š   œžœžœCžœžœžœ˜sK™}Kšžœžœžœ˜Kšœ.˜.K˜šžœžœžœ žœžœ žœžœž˜LKšžœžœ˜—K˜K˜šœ˜K˜ K˜*K˜(Kšœ žœ˜"K˜ —šžœ žœž˜Kšœ,™,šœ˜K˜ K˜*Kšœ$˜$Kšœ žœ˜"K˜ ——Kšœ@˜@Kšœ-˜-šžœž˜Kšœ(™(Kšœ+žœ˜1—K˜Kšœ žœ˜Kšž œ ˜Kšžœžœ˜ Kšœ˜K˜—šžœ˜ Kšœ?˜?Kšœ/˜/Kšœ˜—K˜Kšžœ˜—…—n