Fix lag in TTerminalWindow
[fanfix.git] / src / jexer / tterminal / ECMA48.java
index 69a9da12191dc65fad624177c93935488489c9a6..3702b8bc5bc64d3c9e9e454dbdb8179e464aafc0 100644 (file)
@@ -204,7 +204,7 @@ public class ECMA48 implements Runnable {
      *
      * @param str string to send
      */
-    private void writeRemote(final String str) {
+    public void writeRemote(final String str) {
         if (stopReaderThread) {
             // Reader hit EOF, bail out now.
             close();
@@ -221,6 +221,7 @@ public class ECMA48 implements Runnable {
                 return;
             }
             try {
+                outputStream.flush();
                 for (int i = 0; i < str.length(); i++) {
                     outputStream.write(str.charAt(i));
                 }
@@ -235,6 +236,7 @@ public class ECMA48 implements Runnable {
                 return;
             }
             try {
+                output.flush();
                 output.write(str);
                 output.flush();
             } catch (IOException e) {
@@ -302,6 +304,11 @@ public class ECMA48 implements Runnable {
         }
     }
 
+    /**
+     * The enclosing listening object.
+     */
+    private DisplayListener displayListener;
+
     /**
      * When true, the reader thread is expected to exit.
      */
@@ -523,6 +530,22 @@ public class ECMA48 implements Runnable {
         return width;
     }
 
+    /**
+     * Set the display width.
+     *
+     * @param width the new width
+     */
+    public final void setWidth(final int width) {
+        this.width = width;
+        rightMargin = width - 1;
+        if (currentState.cursorX >= width) {
+            currentState.cursorX = width - 1;
+        }
+        if (savedState.cursorX >= width) {
+            savedState.cursorX = width - 1;
+        }
+    }
+
     /**
      * Physical display height.  We start at 80x24, but the user can resize
      * us bigger/smaller.
@@ -538,6 +561,37 @@ public class ECMA48 implements Runnable {
         return height;
     }
 
+    /**
+     * Set the display height.
+     *
+     * @param height the new height
+     */
+    public final void setHeight(final int height) {
+        int delta = height - this.height;
+        this.height = height;
+        scrollRegionBottom += delta;
+        if (scrollRegionBottom < 0) {
+            scrollRegionBottom = height;
+        }
+        if (scrollRegionTop >= scrollRegionBottom) {
+            scrollRegionTop = 0;
+        }
+        if (currentState.cursorY >= height) {
+            currentState.cursorY = height - 1;
+        }
+        if (savedState.cursorY >= height) {
+            savedState.cursorY = height - 1;
+        }
+        while (display.size() < height) {
+            DisplayLine line = new DisplayLine(currentState.attr);
+            line.setReverseColor(reverseVideo);
+            display.add(line);
+        }
+        while (display.size() > height) {
+            scrollback.add(display.remove(0));
+        }
+    }
+
     /**
      * Top margin of the scrolling region.
      */
@@ -846,6 +900,11 @@ public class ECMA48 implements Runnable {
         arrowKeyMode            = ArrowKeyMode.ANSI;
         keypadMode              = KeypadMode.Numeric;
         wrapLineFlag            = false;
+        if (displayListener != null) {
+            width = displayListener.getDisplayWidth();
+            height = displayListener.getDisplayHeight();
+            rightMargin         = width - 1;
+        }
 
         // Flags
         shiftOut                = false;
@@ -884,11 +943,14 @@ public class ECMA48 implements Runnable {
      * @param outputStream an OutputStream connected to the remote user.  For
      * type == XTERM, outputStream is converted to a Writer with UTF-8
      * encoding.
+     * @param displayListener a callback to the outer display, or null for
+     * default VT100 behavior
      * @throws UnsupportedEncodingException if an exception is thrown when
      * creating the InputStreamReader
      */
     public ECMA48(final DeviceType type, final InputStream inputStream,
-        final OutputStream outputStream) throws UnsupportedEncodingException {
+        final OutputStream outputStream, final DisplayListener displayListener)
+        throws UnsupportedEncodingException {
 
         assert (inputStream != null);
         assert (outputStream != null);
@@ -913,6 +975,7 @@ public class ECMA48 implements Runnable {
             this.output       = null;
             this.outputStream = new BufferedOutputStream(outputStream);
         }
+        this.displayListener  = displayListener;
 
         reset();
         for (int i = 0; i < height; i++) {
@@ -2443,9 +2506,18 @@ public class ECMA48 implements Runnable {
                     } else {
                         // 80 columns
                         columns132 = false;
-                        rightMargin = 79;
+                        if ((displayListener != null)
+                            && (type == DeviceType.XTERM)
+                        ) {
+                            // For xterms, reset to the actual width, not 80
+                            // columns.
+                            width = displayListener.getDisplayWidth();
+                            rightMargin = width - 1;
+                        } else {
+                            rightMargin = 79;
+                            width = rightMargin + 1;
+                        }
                     }
-                    width = rightMargin + 1;
                     // Entire screen is cleared, and scrolling region is
                     // reset
                     eraseScreen(0, 0, height - 1, width - 1, false);
@@ -6011,19 +6083,23 @@ public class ECMA48 implements Runnable {
                     // This is EOF
                     done = true;
                 } else {
-                    for (int i = 0; i < rc; i++) {
-                        int ch = 0;
-                        if (utf8) {
-                            ch = readBufferUTF8[i];
-                        } else {
-                            ch = readBuffer[i];
-                        }
+                    // Don't step on UI events
+                    synchronized (this) {
+                        for (int i = 0; i < rc; i++) {
+                            int ch = 0;
+                            if (utf8) {
+                                ch = readBufferUTF8[i];
+                            } else {
+                                ch = readBuffer[i];
+                            }
 
-                        synchronized (this) {
-                            // Don't step on UI events
                             consume((char)ch);
                         }
                     }
+                    // Permit my enclosing UI to know that I updated.
+                    if (displayListener != null) {
+                        displayListener.displayChanged();
+                    }
                 }
                 // System.err.println("end while loop"); System.err.flush();
             } catch (IOException e) {
@@ -6050,6 +6126,11 @@ public class ECMA48 implements Runnable {
             // SQUASH
         }
 
+        // Permit my enclosing UI to know that I updated.
+        if (displayListener != null) {
+            displayListener.displayChanged();
+        }
+
         // System.err.println("*** run() exiting..."); System.err.flush();
     }