Expose width/height in TApplication constructor, attempt on ECMA48
[fanfix.git] / src / jexer / backend / ECMA48Terminal.java
index 6303f4fc8d0f5240c1287d42bd9876e04cc0222c..ae356107ee9c05f3d049f8bbb8b969a1aea50135 100644 (file)
@@ -40,7 +40,6 @@ import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.LinkedList;
 
@@ -291,6 +290,37 @@ public final class ECMA48Terminal extends LogicalScreen
         }
     }
 
+    /**
+     * Constructor sets up state for getEvent().
+     *
+     * @param listener the object this backend needs to wake up when new
+     * input comes in
+     * @param input an InputStream connected to the remote user, or null for
+     * System.in.  If System.in is used, then on non-Windows systems it will
+     * be put in raw mode; shutdown() will (blindly!) put System.in in cooked
+     * mode.  input is always converted to a Reader with UTF-8 encoding.
+     * @param output an OutputStream connected to the remote user, or null
+     * for System.out.  output is always converted to a Writer with UTF-8
+     * encoding.
+     * @param windowWidth the number of text columns to start with
+     * @param windowHeight the number of text rows to start with
+     * @throws UnsupportedEncodingException if an exception is thrown when
+     * creating the InputStreamReader
+     */
+    public ECMA48Terminal(final Object listener, final InputStream input,
+        final OutputStream output, final int windowWidth,
+        final int windowHeight) throws UnsupportedEncodingException {
+
+        this(listener, input, output);
+
+        // Send dtterm/xterm sequences, which will probably not work because
+        // allowWindowOps is defaulted to false.
+        String resizeString = String.format("\033[8;%d;%dt", windowHeight,
+            windowWidth);
+        this.output.write(resizeString);
+        this.output.flush();
+    }
+
     /**
      * Constructor sets up state for getEvent().
      *
@@ -352,6 +382,11 @@ public final class ECMA48Terminal extends LogicalScreen
         this.output.printf("%s%s", mouse(true), xtermMetaSendsEscape(true));
         this.output.flush();
 
+        // Query the screen size
+        sessionInfo.queryWindowSize();
+        setDimensions(sessionInfo.getWindowWidth(),
+            sessionInfo.getWindowHeight());
+
         // Hang onto the window size
         windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
             sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight());
@@ -360,6 +395,8 @@ public final class ECMA48Terminal extends LogicalScreen
         if (System.getProperty("jexer.ECMA48.rgbColor") != null) {
             if (System.getProperty("jexer.ECMA48.rgbColor").equals("true")) {
                 doRgbColor = true;
+            } else {
+                doRgbColor = false;
             }
         }
 
@@ -368,10 +405,6 @@ public final class ECMA48Terminal extends LogicalScreen
         readerThread = new Thread(this);
         readerThread.start();
 
-        // Query the screen size
-        setDimensions(sessionInfo.getWindowWidth(),
-            sessionInfo.getWindowHeight());
-
         // Clear the screen
         this.output.write(clearAll());
         this.output.flush();
@@ -439,6 +472,11 @@ public final class ECMA48Terminal extends LogicalScreen
         this.output.printf("%s%s", mouse(true), xtermMetaSendsEscape(true));
         this.output.flush();
 
+        // Query the screen size
+        sessionInfo.queryWindowSize();
+        setDimensions(sessionInfo.getWindowWidth(),
+            sessionInfo.getWindowHeight());
+
         // Hang onto the window size
         windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
             sessionInfo.getWindowWidth(), sessionInfo.getWindowHeight());
@@ -447,6 +485,8 @@ public final class ECMA48Terminal extends LogicalScreen
         if (System.getProperty("jexer.ECMA48.rgbColor") != null) {
             if (System.getProperty("jexer.ECMA48.rgbColor").equals("true")) {
                 doRgbColor = true;
+            } else {
+                doRgbColor = false;
             }
         }
 
@@ -455,10 +495,6 @@ public final class ECMA48Terminal extends LogicalScreen
         readerThread = new Thread(this);
         readerThread.start();
 
-        // Query the screen size
-        setDimensions(sessionInfo.getWindowWidth(),
-            sessionInfo.getWindowHeight());
-
         // Clear the screen
         this.output.write(clearAll());
         this.output.flush();
@@ -706,11 +742,6 @@ public final class ECMA48Terminal extends LogicalScreen
      * physical screen
      */
     private String flushString() {
-        if (!dirty) {
-            assert (!reallyCleared);
-            return "";
-        }
-
         CellAttributes attr = null;
 
         StringBuilder sb = new StringBuilder();
@@ -723,7 +754,6 @@ public final class ECMA48Terminal extends LogicalScreen
             flushLine(y, sb, attr);
         }
 
-        dirty = false;
         reallyCleared = false;
 
         String result = sb.toString();
@@ -740,6 +770,8 @@ public final class ECMA48Terminal extends LogicalScreen
     public void flushPhysical() {
         String result = flushString();
         if ((cursorVisible)
+            && (cursorY >= 0)
+            && (cursorX >= 0)
             && (cursorY <= height - 1)
             && (cursorX <= width - 1)
         ) {
@@ -1098,29 +1130,38 @@ public final class ECMA48Terminal extends LogicalScreen
      * @param queue list to append new events to
      */
     private void getIdleEvents(final List<TInputEvent> queue) {
-        Date now = new Date();
+        long nowTime = System.currentTimeMillis();
 
         // Check for new window size
-        long windowSizeDelay = now.getTime() - windowSizeTime;
+        long windowSizeDelay = nowTime - windowSizeTime;
         if (windowSizeDelay > 1000) {
             sessionInfo.queryWindowSize();
             int newWidth = sessionInfo.getWindowWidth();
             int newHeight = sessionInfo.getWindowHeight();
+
             if ((newWidth != windowResize.getWidth())
                 || (newHeight != windowResize.getHeight())
             ) {
+
+                if (debugToStderr) {
+                    System.err.println("Screen size changed, old size " +
+                        windowResize);
+                    System.err.println("                     new size " +
+                        newWidth + " x " + newHeight);
+                }
+
                 TResizeEvent event = new TResizeEvent(TResizeEvent.Type.SCREEN,
                     newWidth, newHeight);
                 windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
                     newWidth, newHeight);
                 queue.add(event);
             }
-            windowSizeTime = now.getTime();
+            windowSizeTime = nowTime;
         }
 
         // ESCDELAY type timeout
         if (state == ParseState.ESCAPE) {
-            long escDelay = now.getTime() - escapeTime;
+            long escDelay = nowTime - escapeTime;
             if (escDelay > 100) {
                 // After 0.1 seconds, assume a true escape character
                 queue.add(controlChar((char)0x1B, false));
@@ -1184,9 +1225,9 @@ public final class ECMA48Terminal extends LogicalScreen
     private void processChar(final List<TInputEvent> events, final char ch) {
 
         // ESCDELAY type timeout
-        Date now = new Date();
+        long nowTime = System.currentTimeMillis();
         if (state == ParseState.ESCAPE) {
-            long escDelay = now.getTime() - escapeTime;
+            long escDelay = nowTime - escapeTime;
             if (escDelay > 250) {
                 // After 0.25 seconds, assume a true escape character
                 events.add(controlChar((char)0x1B, false));
@@ -1206,7 +1247,7 @@ public final class ECMA48Terminal extends LogicalScreen
 
             if (ch == 0x1B) {
                 state = ParseState.ESCAPE;
-                escapeTime = now.getTime();
+                escapeTime = nowTime;
                 return;
             }
 
@@ -1869,14 +1910,27 @@ public final class ECMA48Terminal extends LogicalScreen
                 // We assume that if inputStream has bytes available, then
                 // input won't block on read().
                 int n = inputStream.available();
+
+                /*
+                System.err.printf("inputStream.available(): %d\n", n);
+                System.err.flush();
+                */
+
                 if (n > 0) {
                     if (readBuffer.length < n) {
                         // The buffer wasn't big enough, make it huger
                         readBuffer = new char[readBuffer.length * 2];
                     }
 
+                    // System.err.printf("BEFORE read()\n"); System.err.flush();
+
                     int rc = input.read(readBuffer, 0, readBuffer.length);
-                    // System.err.printf("read() %d", rc); System.err.flush();
+
+                    /*
+                    System.err.printf("AFTER read() %d\n", rc);
+                    System.err.flush();
+                    */
+
                     if (rc == -1) {
                         // This is EOF
                         done = true;
@@ -1892,8 +1946,10 @@ public final class ECMA48Terminal extends LogicalScreen
                             synchronized (eventQueue) {
                                 eventQueue.addAll(events);
                             }
-                            synchronized (listener) {
-                                listener.notifyAll();
+                            if (listener != null) {
+                                synchronized (listener) {
+                                    listener.notifyAll();
+                                }
                             }
                             events.clear();
                         }
@@ -1904,14 +1960,16 @@ public final class ECMA48Terminal extends LogicalScreen
                         synchronized (eventQueue) {
                             eventQueue.addAll(events);
                         }
-                        events.clear();
-                        synchronized (listener) {
-                            listener.notifyAll();
+                        if (listener != null) {
+                            synchronized (listener) {
+                                listener.notifyAll();
+                            }
                         }
+                        events.clear();
                     }
 
-                    // Wait 10 millis for more data
-                    Thread.sleep(10);
+                    // Wait 20 millis for more data
+                    Thread.sleep(20);
                 }
                 // System.err.println("end while loop"); System.err.flush();
             } catch (InterruptedException e) {