diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialPortHandler.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialPortHandler.java index a34e182617a..bd3dfd519d2 100644 --- a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialPortHandler.java +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialPortHandler.java @@ -58,7 +58,7 @@ public class SerialPortHandler implements try { while (fConn.getInputStream() != null && fConn.getInputStream().available() > 0) { int nBytes = fConn.getInputStream().read(bytes); - fControl.writeToTerminal(new String(bytes, 0, nBytes)); + fControl.getRemoteToTerminalOutputStream().write(bytes, 0, nBytes); } } catch (IOException ex) { fControl.displayTextInTerminal(ex.getMessage()); diff --git a/org.eclipse.tm.terminal.ssh/src/org/eclipse/tm/internal/terminal/ssh/SshConnection.java b/org.eclipse.tm.terminal.ssh/src/org/eclipse/tm/internal/terminal/ssh/SshConnection.java index 968007d39c3..ca0ba1434bc 100644 --- a/org.eclipse.tm.terminal.ssh/src/org/eclipse/tm/internal/terminal/ssh/SshConnection.java +++ b/org.eclipse.tm.terminal.ssh/src/org/eclipse/tm/internal/terminal/ssh/SshConnection.java @@ -148,8 +148,7 @@ class SshConnection extends Thread { int n; // read until the thread gets interrupted.... while( (n=in.read(bytes))!=-1) { - // we assume we get ASCII UTF8 bytes - fControl.writeToTerminal(new String(bytes,0,n,"UTF8")); //$NON-NLS-1$ + fControl.getRemoteToTerminalOutputStream().write(bytes,0,n); } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalControl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalControl.java index 45d91169301..17baf916ebc 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalControl.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalControl.java @@ -18,6 +18,7 @@ package org.eclipse.tm.internal.terminal.control.impl; import java.io.IOException; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.net.SocketException; import org.eclipse.jface.dialogs.MessageDialog; @@ -449,24 +450,24 @@ public class TerminalControl implements ITerminalControlForText, ITerminalContro * @see org.eclipse.tm.terminal.ITerminalControl#displayTextInTerminal(java.lang.String) */ public void displayTextInTerminal(String text) { - writeToTerminal(text+"\r\n"); //$NON-NLS-1$ + writeToTerminal("\r\n"+text+"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ } - - public void writeToTerminal(String txt) { - - // Do _not_ use asyncExec() here. Class TerminalText requires that - // its run() and setNewText() methods be called in strictly - // alternating order. If we were to call asyncExec() here, this - // loop might race around and call setNewText() twice in a row, - // which would lose data. - getTerminalText().setNewText(new StringBuffer(txt)); - if(Display.getDefault().getThread()==Thread.currentThread()) - getTerminalText().run(); - else - fDisplay.syncExec(getTerminalText()); + private void writeToTerminal(String text) { + try { + getRemoteToTerminalOutputStream().write(text.getBytes("ISO-8859-1")); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + // should never happen! + e.printStackTrace(); + } catch (IOException e) { + // should never happen! + e.printStackTrace(); + } } - + + public OutputStream getRemoteToTerminalOutputStream() { + return getTerminalText().getOutputStream(); + } protected boolean isLogCharEnabled() { return TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_CHAR); } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalInputStream.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalInputStream.java new file mode 100644 index 00000000000..8ec3f10501b --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/control/impl/TerminalInputStream.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Michael Scharf (Wind River) - initial implementation +*/ + +package org.eclipse.tm.internal.terminal.control.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Timer; +import java.util.TimerTask; + +import org.eclipse.swt.widgets.Display; + +/** + * The main purpose of this class is to start a runnable in the + * display thread when data is available and to pretend no data + * is available after a given amount of time the runnable is running. + * + */ +public class TerminalInputStream extends InputStream { + /** + * The maximum time in milli seconds the {@link #fNotifyChange} runs until + * {@link #ready()} returns false. + */ + private final int fUITimeout; + /** + * The output stream used by the terminal backend to write to the terminal + */ + protected final OutputStream fOutputStream; + /** + * This runnable is called every time some characters are available from... + */ + private final Runnable fNotifyChange; + /** + * A shared timer for all terminals. This times is used to limit the + * time used in the display thread.... + */ + static Timer fgTimer=new Timer(false); + /** + * A blocking byte queue. + */ + private final BoundedByteBuffer fQueue; + + /** + * The maximum amount of data read and written in one shot. + * The timer cannot interrupt reading this amount of data. + * {@link #available()} and {@link #read(byte[], int, int)} + * This is used as optimization, because reading single characters + * can be very inefficient, because each call is synchronized. + */ + // block size must be smaller than the Queue capacity! + final int BLOCK_SIZE=64; + + + /** + * The runnable that si scheduled in the display tread. Takes care of + * the timeout management. It calls the {@link #fNotifyChange} + */ + // synchronized with fQueue! + private Runnable fRunnable; + + /** + * Used as flag to indicate that the current runnable + * has used enough time in the display thread. + * This variable is set by a timer thread after the + * Runnable starts to run in the Display thread after + * {@link #fUITimeout}. + */ + // synchronized with fQueue! + private boolean fEnoughDisplayTime; + + /** + * A byte bounded buffer used to synchronize the input and the output stream. + *

+ * Adapted from BoundedBufferWithStateTracking + * http://gee.cs.oswego.edu/dl/cpj/allcode.java + * http://gee.cs.oswego.edu/dl/cpj/ + *

+ * For some reasons a solution based on + * PipedOutputStream/PipedIntputStream + * does work *very* slowly: + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4404700 + *

+ * + */ + class BoundedByteBuffer { + protected final byte[] fBuffer; // the elements + protected int fPutPos = 0; // circular indices + protected int fTakePos = 0; + protected int fUsedSlots = 0; // the count + public BoundedByteBuffer(int capacity) throws IllegalArgumentException { + // make sure we don't deadlock on too small capacity + if(capacityend) + n=end; + // now block the queue for the time we need to + // add some characters + synchronized(fQueue) { + for(int i=noff;i0)try {read(buff);} catch (IOException e) {break;}}};} + fOutputStream =new TerminalOutputStream(); + fNotifyChange=notifyChange; + fQueue=new BoundedByteBuffer(bufferSize); + fUITimeout=uiTimeout; + } + /** + * Posts the runnable {@link #fNotifyChange} to the display Thread, + * unless the runnable is already scheduled. + * It will make {@link #ready} return false after + * {@link #fUITimeout} milli seconds. + */ + void bytesAreAvailable() { + // synchronize on the Queue to reduce the locks + synchronized(fQueue) { + if(fRunnable==null) { + fRunnable=new Runnable(){ + public void run() { + // protect the access to fRunnable + synchronized(fQueue){ + fRunnable=null; + } + // end the reading after some time + startTimer(fUITimeout); + // and start the real runnable + fNotifyChange.run(); + } + + }; + // TODO: make sure we don't create a display if the display is disposed... + Display.getDefault().asyncExec(fRunnable); + } + } + + } + /** + * Starts a timer that sets {@link #fEnoughDisplayTime} to + * true after milliSec. + * @param milliSec The time after which fEnoughDisplayTime is set to true. + */ + void startTimer(int milliSec) { + synchronized(fQueue) { + fEnoughDisplayTime=false; + } + fgTimer.schedule(new TimerTask(){ + public void run() { + synchronized(fQueue) { + fEnoughDisplayTime=true; + // there is some data available + if(fQueue.size()>0) { + // schedule a new runnable to do the work + bytesAreAvailable(); + } + } + }}, milliSec); + } + /** + * @return the output stream used by the backend to write to the terminal. + */ + public OutputStream getOutputStream() { + return fOutputStream; + } + /** + * Must be called in the Display Thread! + * @return true if a character is available for the terminal to show. + */ + public int available() { + int available; + synchronized(fQueue) { + if(fEnoughDisplayTime) + return 0; + available=fQueue.size(); + } + // Limit the available amount of data. + // else our trick of limiting the time spend + // reading might not work. + if(available>BLOCK_SIZE) + available=BLOCK_SIZE; + return available; + } + /** + * @return the next available byte. Check with {@link #available} + * if characters are available. + */ + public int read() throws IOException { + try { + return fQueue.read(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return -1; + } + } + /** + * Closing a ByteArrayInputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + *

+ */ + public void close() throws IOException { + } + + public int read(byte[] cbuf, int off, int len) throws IOException { + int n=0; + // read as much as we can using a single synchronized statement + synchronized (fQueue) { + try { + // The assumption is that the caller has used available to + // check if bytes are available! That's why we don't check + // for fEnoughDisplayTime! + // Make sure that not more than BLOCK_SIZE is read in one call + while(fQueue.size()>0 && n * @author Chris Thew */ -public class TerminalText implements Runnable, ControlListener { +public class TerminalText implements ControlListener { /** This is a character processing state: Initial state. */ protected static final int ANSISTATE_INITIAL = 0; @@ -88,19 +92,6 @@ public class TerminalText implements Runnable, ControlListener { */ protected StyledText text; - /** - * This field holds the characters received from the remote host before they - * are displayed to the user. Method {@link #processNewText()} scans this - * text looking for ANSI control characters and escape sequences. - */ - protected StringBuffer newText; - - /** - * This field holds the index of the current character while the text stored - * in field {@link #newText} is being processed. - */ - protected int characterIndex = 0; - /** * This field holds the width of a character (in pixels) for the font used * to display text. @@ -214,12 +205,6 @@ public class TerminalText implements Runnable, ControlListener { */ protected boolean reverseVideo = false; - /** - * This field holds the time (in milliseconds) of the previous call to - * method {@link #SetNewText()}. - */ - static long LastNewOutputTime = 0; - /** * Color object representing the color black. The Color class requires us to * call dispose() on this object when we no longer need it. We do that in @@ -278,6 +263,8 @@ public class TerminalText implements Runnable, ControlListener { protected boolean fLimitOutput; protected int fBufferLineLimit; + final TerminalInputStream fTerminalInputStream; + final Reader fReader; /** * The constructor. */ @@ -291,6 +278,19 @@ public class TerminalText implements Runnable, ControlListener { for (int i = 0; i < ansiParameters.length; ++i) { ansiParameters[i] = new StringBuffer(); } + fTerminalInputStream=new TerminalInputStream(1024, 100, new Runnable() { + public void run() { + processText(); + }}); + Reader reader=null; + try { + // TODO convert byte to char using "ISO-8859-1" + reader=new InputStreamReader(fTerminalInputStream,"ISO-8859-1"); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + // should never happen! + e.printStackTrace(); + } + fReader=reader; } /** @@ -346,64 +346,17 @@ public class TerminalText implements Runnable, ControlListener { /** * This method is required by interface ControlListener. It allows us to - * know when the StyledText widget is resized. This method must be - * synchronized to prevent it from executing at the same time as run(), - * which displays new text. We can't have the fields that represent the - * dimensions of the terminal changing while we are rendering text. + * know when the StyledText widget is resized. */ - public synchronized void controlResized(ControlEvent event) { + public void controlResized(ControlEvent event) { Logger.log("entered"); //$NON-NLS-1$ adjustTerminalDimensions(); } /** - * This method sets field {@link #newText} to a new value. This method must - * not execute at the same time as methods {@link #run()} and {@link - * #clearTerminal()}. - *

- * - * IMPORTANT: This method must be called in strict alternation with method - * {@link #run()}. - *

- * - * @param newBuffer - * The new buffer containing characters received from the remote - * host. + * This method erases all text from the Terminal view. */ - public synchronized void setNewText(StringBuffer newBuffer) { - if (Logger.isLogEnabled()) { - Logger.log("new text: '" + Logger.encode(newBuffer.toString()) + "'"); //$NON-NLS-1$ //$NON-NLS-2$ - } - newText = newBuffer; - - // When continuous output is being processed by the Terminal view code, it - // consumes nearly 100% of the CPU. This fixes that. If this method is called - // too frequently, we explicitly sleep for a short time so that the thread - // executing this function (which is the thread reading from the socket or - // serial port) doesn't consume 100% of the CPU. Without this code, the - // Workbench GUI is practically hung when there is continuous output in the - // Terminal view. - - long CurrentTime = System.currentTimeMillis(); - - if (CurrentTime - LastNewOutputTime < 250 && newBuffer.length() > 10) { - try { - Thread.sleep(50); - } catch (InterruptedException ex) { - // Ignore. - } - } - - LastNewOutputTime = CurrentTime; - } - - /** - * This method erases all text from the Terminal view. This method is called - * when the user chooses "Clear all" from the Terminal view context menu, so - * we need to serialize this method with methods {@link #run()} and {@link - * #setNewText(StringBuffer)}. - */ - public synchronized void clearTerminal() { + public void clearTerminal() { Logger.log("entered"); //$NON-NLS-1$ text.setText(""); //$NON-NLS-1$ cursorColumn = 0; @@ -412,12 +365,9 @@ public class TerminalText implements Runnable, ControlListener { /** * This method is called when the user changes the Terminal view's font. We * attempt to recompute the pixel width of the new font's characters and fix - * the terminal's dimensions. This method must be synchronized to prevent it - * from executing at the same time as run(), which displays new text. We - * can't have the fields that represent the dimensions of the terminal - * changing while we are rendering text. + * the terminal's dimensions. */ - public synchronized void fontChanged() { + public void fontChanged() { Logger.log("entered"); //$NON-NLS-1$ characterPixelWidth = 0; @@ -425,7 +375,6 @@ public class TerminalText implements Runnable, ControlListener { if (text != null) adjustTerminalDimensions(); } - /** * This method executes in the Display thread to process data received from * the remote host by class {@link TelnetConnection} and @@ -434,7 +383,7 @@ public class TerminalText implements Runnable, ControlListener { *

* These connectors write text to the terminal's buffer through * {@link TerminalControl#writeToTerminal(String)} and then have - * this run method exectued in the display thread. This method + * this run method executed in the display thread. This method * must not execute at the same time as methods * {@link #setNewText(StringBuffer)} and {@link #clearTerminal()}. *

@@ -442,9 +391,7 @@ public class TerminalText implements Runnable, ControlListener { * {@link #setNewText(StringBuffer)}. *

*/ - public synchronized void run() { - Logger.log("entered"); //$NON-NLS-1$ - + void processText() { try { // This method can be called just after the user closes the view, so we // make sure not to cause a widget-disposed exception. @@ -471,20 +418,23 @@ public class TerminalText implements Runnable, ControlListener { // ISSUE: Is this causing the scroll-to-bottom-on-output behavior? text.setCaretOffset(caretOffset); - - processNewText(); + try { + processNewText(); + } catch (IOException e) { + Logger.logException(e); + } caretOffset = text.getCaretOffset(); } catch (Exception ex) { Logger.logException(ex); } } - /** * This method scans the newly received text, processing ANSI control * characters and escape sequences and displaying normal text. + * @throws IOException */ - protected void processNewText() { + protected void processNewText() throws IOException { Logger.log("entered"); //$NON-NLS-1$ // Stop the StyledText widget from redrawing while we manipulate its contents. @@ -494,10 +444,8 @@ public class TerminalText implements Runnable, ControlListener { // Scan the newly received text. - characterIndex = 0; - - while (characterIndex < newText.length()) { - char character = newText.charAt(characterIndex); + while (hasNextChar()) { + char character = getNextChar(); switch (ansiState) { case ANSISTATE_INITIAL: @@ -530,7 +478,7 @@ public class TerminalText implements Runnable, ControlListener { break; default: - processNonControlCharacters(); + processNonControlCharacters(character); break; } break; @@ -614,15 +562,12 @@ public class TerminalText implements Runnable, ControlListener { ansiState = ANSISTATE_INITIAL; break; } - - ++characterIndex; } // Allow the StyledText widget to redraw itself. text.setRedraw(true); } - /** * This method is called when we have parsed an OS Command escape sequence. * The only one we support is "\e]0;...\u0007", which sets the terminal @@ -1093,7 +1038,7 @@ public class TerminalText implements Runnable, ControlListener { /** * Delete one or more lines of text. Any lines below the deleted lines move - * up, which we implmement by appending newlines to the end of the text. + * up, which we implement by appending newlines to the end of the text. */ protected void processAnsiCommand_M() { int totalLines = text.getLineCount(); @@ -1355,9 +1300,9 @@ public class TerminalText implements Runnable, ControlListener { /** * This method processes a single parameter character in an ANSI escape - * sequence. Paramters are the (optional) characters between the leading + * sequence. Parameters are the (optional) characters between the leading * "\e[" and the command character in an escape sequence (e.g., in the - * escape sequence "\e[20;10H", the paramter characters are "20;10"). + * escape sequence "\e[20;10H", the parameter characters are "20;10"). * Parameters are integers separated by one or more ';'s. */ protected void processAnsiParameterCharacter(char ch) { @@ -1368,44 +1313,35 @@ public class TerminalText implements Runnable, ControlListener { ansiParameters[nextAnsiParameter].append(ch); } } - /** * This method processes a contiguous sequence of non-control characters. * This is a performance optimization, so that we don't have to insert or * append each non-control character individually to the StyledText widget. * A non-control character is any character that passes the condition in the * below while loop. + * @throws IOException */ - protected void processNonControlCharacters() { - int firstNonControlCharacterIndex = characterIndex; - int newTextLength = newText.length(); - char character = newText.charAt(characterIndex); - + protected void processNonControlCharacters(char character) throws IOException { + StringBuffer buffer=new StringBuffer(); + buffer.append(character); // Identify a contiguous sequence of non-control characters, starting at // firstNonControlCharacterIndex in newText. - - while (character != '\u0000' && character != '\b' && character != '\t' - && character != '\u0007' && character != '\n' - && character != '\r' && character != '\u001b') { - ++characterIndex; - - if (characterIndex >= newTextLength) + while(hasNextChar()) { + character=getNextChar(); + if(character == '\u0000' || character == '\b' || character == '\t' + || character == '\u0007' || character == '\n' + || character == '\r' || character == '\u001b') { + pushBackChar(character); break; - - character = newText.charAt(characterIndex); + } + buffer.append(character); } - - // Move characterIndex back by one character because it gets incremented at the - // bottom of the loop in processNewText(). - - --characterIndex; - int preDisplayCaretOffset = text.getCaretOffset(); // Now insert the sequence of non-control characters in the StyledText widget // at the location of the cursor. - displayNewText(firstNonControlCharacterIndex, characterIndex); + displayNewText(buffer.toString()); // If any one of the current font style, foreground color or background color // differs from the defaults, apply the current style to the newly displayed @@ -1438,23 +1374,18 @@ public class TerminalText implements Runnable, ControlListener { * text being displayed by this method (this includes newlines, carriage * returns, and tabs). *

- * - * @param first - * The index (within newText) of the first character to display. - * @param last - * The index (within newText) of the last character to display. */ - protected void displayNewText(int first, int last) { + protected void displayNewText(String buffer) { if (text.getCaretOffset() == text.getCharCount()) { // The cursor is at the very end of the terminal's text, so we append the // new text to the StyledText widget. - displayNewTextByAppending(first, last); + displayNewTextByAppending(buffer); } else { // The cursor is not at the end of the screen's text, so we have to // overwrite existing text. - displayNewTextByOverwriting(first, last); + displayNewTextByOverwriting(buffer); } } @@ -1467,14 +1398,11 @@ public class TerminalText implements Runnable, ControlListener { * text being displayed by this method (this includes newlines, carriage * returns, and tabs). *

- * - * @param first - * The index (within newText) of the first character to display. - * @param last - * The index (within newText) of the last character to display. */ - protected void displayNewTextByAppending(int first, int last) { - int numCharsToOutput = last - first + 1; + protected void displayNewTextByAppending(String newText) { + int first=0; + int last=newText.length()-1; + int numCharsToOutput = newText.length(); int availableSpaceOnLine = widthInColumns - cursorColumn; if (numCharsToOutput >= availableSpaceOnLine) { @@ -1525,16 +1453,13 @@ public class TerminalText implements Runnable, ControlListener { * text being displayed by this method (this includes newlines, carriage * returns, and tabs). *

- * - * @param first - * The index (within newText) of the first character to display. - * @param last - * The index (within newText) of the last character to display. */ - protected void displayNewTextByOverwriting(int first, int last) { + protected void displayNewTextByOverwriting(String newText) { // First, break new text into segments, based on where it needs to line wrap, // so that each segment contains text that will appear on a separate // line. + int first=0; + int last=newText.length()-1; List textSegments = new ArrayList(100); @@ -1569,7 +1494,7 @@ public class TerminalText implements Runnable, ControlListener { if (caretOffset == text.getCharCount()) { // The cursor is at the end of the text, so just append the current - // segement along with a newline. + // segment along with a newline. text.append(segment); @@ -1823,7 +1748,7 @@ public class TerminalText implements Runnable, ControlListener { // terminal. ITerminalConnector telnetConnection = terminal.getTerminalConnection(); - + // TODO MSA: send only if dimensions have really changed! if (telnetConnection != null && widthInColumns != 0 && heightInLines != 0) { telnetConnection.setTerminalSize(widthInColumns, heightInLines); } @@ -1898,7 +1823,7 @@ public class TerminalText implements Runnable, ControlListener { } /** - * This method returns the relative line number of the line comtaining the + * This method returns the relative line number of the line containing the * cursor. The returned line number is relative to the topmost visible line, * which has relative line number 0. * @@ -2077,4 +2002,43 @@ public class TerminalText implements Runnable, ControlListener { protected void setLimitOutput(boolean limitOutput) { fLimitOutput = limitOutput; } + + public OutputStream getOutputStream() { + return fTerminalInputStream.getOutputStream(); + } + + /** + * Buffer for {@link #pushBackChar(char)}. + */ + private int fNextChar=-1; + private char getNextChar() throws IOException { + int c=-1; + if(fNextChar!=-1) { + c= fNextChar; + fNextChar=-1; + } else { + c = fReader.read(); + } + // TODO: better end of file handling + if(c==-1) + c=0; + return (char)c; + } + + private boolean hasNextChar() throws IOException { + if(fNextChar>=0) + return true; + return fReader.ready(); + } + + /** + * Put back one character to the stream. This method can push + * back exactly one character. The character is the next character + * returned by {@link #getNextChar} + * @param c the character to be pushed back. + */ + void pushBackChar(char c) { + //assert fNextChar!=-1: "Already a character waiting:"+fNextChar; //$NON-NLS-1$ + fNextChar=c; + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnection.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnection.java index 44ebd2f1dc3..bdb5655bac4 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnection.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnection.java @@ -280,8 +280,8 @@ public class TelnetConnection extends Thread implements TelnetCodes { return localEcho; } - private void writeToTerminal(String string) { - terminalControl.writeToTerminal(string); + private void displayTextInTerminal(String string) { + terminalControl.displayTextInTerminal(string); } /** @@ -304,7 +304,7 @@ public class TelnetConnection extends Thread implements TelnetCodes { // Announce to the user that the remote endpoint has closed the // connection. - writeToTerminal("\r"+TelnetMessages.CONNECTION_CLOSED_BY_FOREIGN_HOST+"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ + displayTextInTerminal(TelnetMessages.CONNECTION_CLOSED_BY_FOREIGN_HOST); // Tell the ITerminalControl object that the connection is // closed. @@ -321,7 +321,7 @@ public class TelnetConnection extends Thread implements TelnetCodes { int nProcessedBytes = processTelnetProtocol(nRawBytes); if (nProcessedBytes > 0) { - writeToTerminal(new String(processedBytes, 0, nProcessedBytes)); + terminalControl.getRemoteToTerminalOutputStream().write(processedBytes, 0, nProcessedBytes); } } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnector.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnector.java index 91081a203e7..03fc62c9ef2 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnector.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/internal/terminal/telnet/TelnetConnector.java @@ -135,8 +135,11 @@ public class TelnetConnector implements ITerminalConnector { public void setTelnetConnection(TelnetConnection connection) { fTelnetConnection=connection; } - public void writeToTerminal(String txt) { - fControl.writeToTerminal(txt); + public void displayTextInTerminal(String text) { + fControl.displayTextInTerminal(text); + } + public OutputStream getRemoteToTerminalOutputStream () { + return fControl.getRemoteToTerminalOutputStream(); } public void setState(TerminalState state) { diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java index 53f9460b7e7..a34830b3e3a 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.eclipse.tm.terminal; +import java.io.OutputStream; + import org.eclipse.swt.widgets.Shell; /** @@ -46,10 +48,11 @@ public interface ITerminalControl { void displayTextInTerminal(String text); /** - * Write a string directly to the terminal. - * @param txt + * @return a stream used to write to the terminal. Any bytes written to this + * stream appear in the terminal or are interpreted by the emulator as + * control sequences. */ - void writeToTerminal(String txt); + OutputStream getRemoteToTerminalOutputStream(); /** * Set the title of the terminal view.