DIRECTORY ImplErrors USING [UserErrorQuery], Process USING [Detach, GetCurrent, MsecToTicks, SetTimeout, Ticks], Rope USING [Concat, Fetch, FromProc, Length, ROPE], TextEdit USING [InsertRope, InsertString], TextNode USING [NarrowToTextNode, Location, pZone, 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 ImplErrors, Process, Rope, TextEdit, TextNode, TEditInput, TEditInputOps, TEditLocks, TEditRefresh, TEditSelection EXPORTS TEditInputOps SHARES TEditInputOps = BEGIN OPEN TEditSelection; editRepaintProcess: PROCESS _ NIL; repaintDone: CONDITION; bufferMaxlen: CARDINAL _ 32; inputBuffer: REF TEXT _ TextNode.pZone.NEW[TEXT[bufferMaxlen]]; inputRope: Rope.ROPE; BufferedInsertChar: PUBLIC ENTRY PROCEDURE [char: CHARACTER] = BEGIN 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 editRepaintProcess=NIL THEN TRUSTED { Process.Detach[editRepaintProcess _ FORK Repaint[]] }; END; BufferedInsertText: PUBLIC PROCEDURE [text: Rope.ROPE] = BEGIN FOR n: LONG INTEGER IN [0..Rope.Length[text]) DO BufferedInsertChar[Rope.Fetch[text, n]]; ENDLOOP; END; WaitForInsertToFinish: PUBLIC ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; -- release lock WHILE editRepaintProcess # NIL DO WAIT repaintDone; ENDLOOP; END; Repaint: PROCEDURE = BEGIN Cleanup: PROC = { TEditSelection.UnlockSel[primary]; IF docLock THEN TEditLocks.Unlock[root]; IF tSel # NIL THEN Free[tSel]; NotifyDone }; root: TextNode.Ref; docLock, caretVisible: BOOL _ FALSE; tSel: TEditDocument.Selection; BEGIN ENABLE BEGIN UNWIND => Cleanup; ABORTED => GOTO Quit; ANY => IF ImplErrors.UserErrorQuery[] THEN CONTINUE; END; WaitForMoreInput: ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; -- release lock WAIT untilTimesOutInALittleWhile; END; TEditSelection.LockSel[primary, "TEditBufferedInputImplRepaint"]; caretVisible _ TEditSelection.CaretVisible[]; IF ~TEditInputOps.CheckReadonly[pSel] OR (root _ TEditSelection.SelectionRoot[pSel])=NIL THEN { Cleanup[]; RETURN }; [] _ TEditLocks.Lock[root, "TEditBufferedInputImplMakeEdits"]; docLock _ TRUE; tSel _ Alloc[]; WHILE MakeEdits[root, tSel, caretVisible] DO IF inputRope=NIL AND inputBuffer.length Cleanup; END END; NotifyDone: ENTRY PROC = TRUSTED INLINE { IF Process.GetCurrent[]=editRepaintProcess THEN editRepaintProcess _ NIL; BROADCAST repaintDone}; MakeEdits: ENTRY PROCEDURE [ root: TextNode.Ref, tSel: TEditDocument.Selection, caretVisible: BOOL] RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; pos: TextNode.Location _ InsertionPoint[pSel]; IF root=NIL OR pos.node=NIL OR (inputRope=NIL AND inputBuffer.length=0) THEN {editRepaintProcess _ NIL; RETURN[FALSE]}; -- done 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 -- insert it in front of the inputBuffer string [] _ 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 -- after repaint finishes, do an autoscroll TEditRefresh.ScrollToEndOfSel[tSel.viewer, TRUE]; inputBuffer.length _ 0; inputRope _ NIL; BROADCAST bufferClear; RETURN[TRUE]; END; aLittleWhile: Process.Ticks = Process.MsecToTicks[50]; untilTimesOutInALittleWhile, bufferClear: CONDITION; TRUSTED {Process.SetTimeout[@untilTimesOutInALittleWhile, aLittleWhile]}; TRUSTED {Process.SetTimeout[@bufferClear, aLittleWhile]}; END. -- TEditBufferedInputImpl.mesa Edited by Paxton on November 24, 1982 9:50 am Last Edited by: Maxwell, January 6, 1983 11:39 am Get document and selection locks outside of monitor to avoid deadlock with someone doing an insert char while holding a lock. ʘJšÏcL™LJšÏk1™1Jšž ˜ ˜Jšœ žœ˜"Jšœžœ6˜CJšœžœ#žœ˜3Jšœ žœ˜*Jšœ žœ*˜8Jšœžœ ˜ Jšœ žœ˜ J˜Jšœ žœ˜ Jšœ žœ˜&Jšœžœp˜„J˜—Jšœž ˜%J˜Jšžœs˜zJšžœ˜Jšžœž˜J˜Jšžœ˜J˜Jšœžœžœ˜"J˜Jšœ ž œ˜J˜Jšœžœ˜Jš œ žœžœžœžœ˜?Jšœžœ˜J˜š Ïnœžœžœž œž œž˜DJšžœžœžœ˜&Jšœžœ˜šžœ$žœ˜:šžœžœ˜6Jšœžœ˜JšŸœžœžœžœ$˜?Jšœ žœ*ž˜:Jšœ)˜)Jšœ˜Jšžœ˜—Jšž œ˜EJšžœ:˜LJšžœ˜—J˜'J˜,šžœžœžœžœ˜(Jšœ$žœ˜6—Jšžœ˜J˜—š Ÿœžœž œ žœž˜>š žœžœžœžœž˜0J˜(Jšžœ˜—Jšžœ˜J˜—š Ÿœžœžœž œž˜5Jšžœžœžœ˜&Jšžœžœžœ žœ˜Jšœ žœ˜Jšœ˜šžœ%ž˜,Jšžœ žœžœ!žœ˜MJšžœ˜—Jšœ˜Jšžœ˜Jšžœ˜J˜—š Ÿ œžœžœžœžœ˜)Jšžœ)žœžœ˜IJšž œ˜—J˜šŸ œžœž œ˜JšœAžœ˜FJ™}Jšžœžœž˜Jšžœžœžœ˜Jšœ.˜.J˜šžœžœžœ žœžœ žœžœž˜LJšœžœžœžœ˜2—J˜J˜šœ˜J˜ J˜*J˜(Jšœ žœ˜"J˜ —šžœ žœžœ/˜Ešœ˜J˜ J˜*Jšœ$˜$Jšœ žœ˜"J˜ ——Jšœ@˜@Jšœ-˜-šžœžœ+˜@Jšœ+žœ˜1—J˜Jšœ žœ˜Jšž œ ˜Jšžœžœ˜ Jšžœ˜J˜—J˜6Jšœ*ž œ˜4J˜JšžœB˜IJšžœ2˜9J˜Jšžœ˜J˜—…—î´