Fix lag in TTerminalWindow
authorKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 24 Aug 2017 20:58:46 +0000 (16:58 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Thu, 24 Aug 2017 20:58:46 +0000 (16:58 -0400)
src/jexer/TApplication.java
src/jexer/TTerminalWindow.java
src/jexer/menu/TMenu.java
src/jexer/tterminal/ECMA48.java

index d74d6c5aa98c964e7ee737e3ea960aab0b79eebb..b7c5f8ef51e5c63f30605d840d8dab0967f1b86b 100644 (file)
@@ -283,6 +283,10 @@ public class TApplication implements Runnable {
      * Wake the sleeping active event handler.
      */
     private void wakeEventHandler() {
+        if (!started) {
+            return;
+        }
+
         if (secondaryEventHandler != null) {
             synchronized (secondaryEventHandler) {
                 secondaryEventHandler.notify();
@@ -426,6 +430,11 @@ public class TApplication implements Runnable {
      */
     private List<TTimer> timers;
 
+    /**
+     * When true, the application has been started.
+     */
+    private volatile boolean started = false;
+
     /**
      * When true, exit the application.
      */
@@ -931,6 +940,8 @@ public class TApplication implements Runnable {
         primaryEventHandler = new WidgetEventHandler(this, true);
         (new Thread(primaryEventHandler)).start();
 
+        started = true;
+
         while (!quit) {
             synchronized (this) {
                 boolean doWait = false;
@@ -2383,6 +2394,24 @@ public class TApplication implements Runnable {
         }
     }
 
+    /**
+     * Post an event to process.
+     *
+     * @param event new event to add to the queue
+     */
+    public final void postEvent(final TInputEvent event) {
+        synchronized (this) {
+            synchronized (fillEventQueue) {
+                fillEventQueue.add(event);
+            }
+            if (debugThreads) {
+                System.err.println(System.currentTimeMillis() + " " +
+                    Thread.currentThread() + " postEvent() wake up main");
+            }
+            this.notify();
+        }
+    }
+
     /**
      * Post an event to process and turn off the menu.
      *
index 31834eebc2324bc02f9e7261277d3994a108ca1b..af319c92d92ea3308037a998463a6c3f777e9a12 100644 (file)
@@ -39,8 +39,10 @@ import java.util.ResourceBundle;
 import jexer.bits.Cell;
 import jexer.bits.CellAttributes;
 import jexer.event.TKeypressEvent;
+import jexer.event.TMenuEvent;
 import jexer.event.TMouseEvent;
 import jexer.event.TResizeEvent;
+import jexer.menu.TMenu;
 import jexer.tterminal.DisplayLine;
 import jexer.tterminal.DisplayListener;
 import jexer.tterminal.ECMA48;
@@ -187,6 +189,20 @@ public class TTerminalWindow extends TScrollableWindow
         newStatusBar(i18n.getString("statusBarRunning"));
     }
 
+    /**
+     * Public constructor spawns a custom command line.
+     *
+     * @param application TApplication that manages this window
+     * @param x column relative to parent
+     * @param y row relative to parent
+     * @param commandLine the command line to execute
+     */
+    public TTerminalWindow(final TApplication application, final int x,
+        final int y, final String commandLine) {
+
+        this(application, x, y, RESIZABLE, commandLine);
+    }
+
     /**
      * Public constructor spawns a custom command line.
      *
@@ -399,7 +415,7 @@ public class TTerminalWindow extends TScrollableWindow
      * Called by emulator when fresh data has come in.
      */
     public void displayChanged() {
-        doRepaint();
+        getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT));
     }
 
     /**
@@ -439,6 +455,13 @@ public class TTerminalWindow extends TScrollableWindow
         }
     }
 
+    /**
+     * Hook for subclasses to be notified of the shell termination.
+     */
+    public void onShellExit() {
+        getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT));
+    }
+
     /**
      * Copy out variables from the emulator that TTerminal has to expose on
      * screen.
@@ -478,6 +501,7 @@ public class TTerminalWindow extends TScrollableWindow
                     clearShortcutKeypresses();
                     statusBar.setText(MessageFormat.format(i18n.
                             getString("statusBarCompleted"), rc));
+                    onShellExit();
                 } catch (IllegalThreadStateException e) {
                     // The emulator thread has exited, but the shell Process
                     // hasn't figured that out yet.  Do nothing, we will see
@@ -495,6 +519,7 @@ public class TTerminalWindow extends TScrollableWindow
                     clearShortcutKeypresses();
                     statusBar.setText(MessageFormat.format(i18n.
                             getString("statusBarCompleted"), rc));
+                    onShellExit();
                 } catch (IllegalThreadStateException e) {
                     // The shell is still running, do nothing.
                 }
index b9641e1eab4a31fd0179ffed4cb53e4e040d66e8..667673b642c4f340dd91b411fe38e3904d0f5687 100644 (file)
@@ -445,7 +445,7 @@ public final class TMenu extends TWindow {
 
         case MID_OPEN_FILE:
             label = i18n.getString("menuOpen");
-            key = kbAltO;
+            key = kbF3;
             break;
 
         case MID_CUT:
index 31bb5b1573cda8d66922036a40027e117b52e83f..3702b8bc5bc64d3c9e9e454dbdb8179e464aafc0 100644 (file)
@@ -6083,16 +6083,16 @@ 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);
                         }
                     }
@@ -6126,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();
     }