From b2d49e0f15810a35a206e88c9bad11b053ed65fc Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Thu, 24 Aug 2017 16:58:46 -0400 Subject: [PATCH] Fix lag in TTerminalWindow --- src/jexer/TApplication.java | 29 +++++++++++++++++++++++++++++ src/jexer/TTerminalWindow.java | 27 ++++++++++++++++++++++++++- src/jexer/menu/TMenu.java | 2 +- src/jexer/tterminal/ECMA48.java | 23 ++++++++++++++--------- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index d74d6c5..b7c5f8e 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -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 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. * diff --git a/src/jexer/TTerminalWindow.java b/src/jexer/TTerminalWindow.java index 31834ee..af319c9 100644 --- a/src/jexer/TTerminalWindow.java +++ b/src/jexer/TTerminalWindow.java @@ -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. } diff --git a/src/jexer/menu/TMenu.java b/src/jexer/menu/TMenu.java index b9641e1..667673b 100644 --- a/src/jexer/menu/TMenu.java +++ b/src/jexer/menu/TMenu.java @@ -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: diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index 31bb5b1..3702b8b 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -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(); } -- 2.27.0