From bb35d91958450cc7152d2063f1d6cd34c15e2a3d Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Thu, 19 Mar 2015 23:51:33 -0400 Subject: [PATCH] first screenshot attempt --- README.md | 10 +- screenshots/screenshot1.png | Bin 0 -> 9257 bytes src/jexer/TApplication.java | 279 ++++++++++++++++--------------- src/jexer/io/ECMA48Terminal.java | 2 +- src/jexer/tterminal/ECMA48.java | 131 ++++++++------- 5 files changed, 226 insertions(+), 196 deletions(-) create mode 100644 screenshots/screenshot1.png diff --git a/README.md b/README.md index 8d8ea20..058eb6f 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,13 @@ Some arbitrary design decisions had to be made when either the obviously expected behavior did not happen or when a specification was ambiguous. This section describes such issues. + TTerminalWindow + --------------- + + - TTerminalWindow will hang on input from the remote if the + TApplication is exited before closing the TTerminalWindow. This + is due to a Java limitation/interaction between blocking reads + (necessary to get UTF8 translation correct) and file streams. Roadmap @@ -107,7 +114,6 @@ Many tasks remain before calling this version 1.0: 0.0.4: - Bugs - - TTimer is jittery with I/O - TSubMenu keyboard mnemonic not working - Making TMenu keyboard accelerators active/inactive - TDirectoryList cannot be navigated only with keyboard @@ -144,3 +150,5 @@ Wishlist features (2.0): Screenshots ----------- +![Several Windows Open Including A Terminal](/screenshots/screenshot1.png?raw=true "Several Windows Open Including A Terminal") + diff --git a/screenshots/screenshot1.png b/screenshots/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..10e9ec2a2274901aff47ed0c308c090c18347df2 GIT binary patch literal 9257 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 a`?7eyn1zLE{VoK9US`IYM)?OEBK`*~6KMhf literal 0 HcmV?d00001 diff --git a/src/jexer/TApplication.java b/src/jexer/TApplication.java index e710895..5813d6f 100644 --- a/src/jexer/TApplication.java +++ b/src/jexer/TApplication.java @@ -1019,20 +1019,22 @@ public class TApplication { * @param window the window to remove */ public final void closeWindow(final TWindow window) { - int z = window.getZ(); - window.setZ(-1); - Collections.sort(windows); - windows.remove(0); - TWindow activeWindow = null; - for (TWindow w: windows) { - if (w.getZ() > z) { - w.setZ(w.getZ() - 1); - if (w.getZ() == 0) { - w.setActive(true); - assert (activeWindow == null); - activeWindow = w; - } else { - w.setActive(false); + synchronized (windows) { + int z = window.getZ(); + window.setZ(-1); + Collections.sort(windows); + windows.remove(0); + TWindow activeWindow = null; + for (TWindow w: windows) { + if (w.getZ() > z) { + w.setZ(w.getZ() - 1); + if (w.getZ() == 0) { + w.setActive(true); + assert (activeWindow == null); + activeWindow = w; + } else { + w.setActive(false); + } } } } @@ -1071,35 +1073,39 @@ public class TApplication { return; } - // Swap z/active between active window and the next in the list - int activeWindowI = -1; - for (int i = 0; i < windows.size(); i++) { - if (windows.get(i).getActive()) { - activeWindowI = i; - break; + synchronized (windows) { + + // Swap z/active between active window and the next in the list + int activeWindowI = -1; + for (int i = 0; i < windows.size(); i++) { + if (windows.get(i).getActive()) { + activeWindowI = i; + break; + } } - } - assert (activeWindowI >= 0); + assert (activeWindowI >= 0); - // Do not switch if a window is modal - if (windows.get(activeWindowI).isModal()) { - return; - } + // Do not switch if a window is modal + if (windows.get(activeWindowI).isModal()) { + return; + } - int nextWindowI; - if (forward) { - nextWindowI = (activeWindowI + 1) % windows.size(); - } else { - if (activeWindowI == 0) { - nextWindowI = windows.size() - 1; + int nextWindowI; + if (forward) { + nextWindowI = (activeWindowI + 1) % windows.size(); } else { - nextWindowI = activeWindowI - 1; + if (activeWindowI == 0) { + nextWindowI = windows.size() - 1; + } else { + nextWindowI = activeWindowI - 1; + } } - } - windows.get(activeWindowI).setActive(false); - windows.get(activeWindowI).setZ(windows.get(nextWindowI).getZ()); - windows.get(nextWindowI).setZ(0); - windows.get(nextWindowI).setActive(true); + windows.get(activeWindowI).setActive(false); + windows.get(activeWindowI).setZ(windows.get(nextWindowI).getZ()); + windows.get(nextWindowI).setZ(0); + windows.get(nextWindowI).setActive(true); + + } // synchronized (windows) // Refresh repaint = true; @@ -1111,17 +1117,19 @@ public class TApplication { * @param window new window to add */ public final void addWindow(final TWindow window) { - // Do not allow a modal window to spawn a non-modal window - if ((windows.size() > 0) && (windows.get(0).isModal())) { - assert (window.isModal()); - } - for (TWindow w: windows) { - w.setActive(false); - w.setZ(w.getZ() + 1); + synchronized (windows) { + // Do not allow a modal window to spawn a non-modal window + if ((windows.size() > 0) && (windows.get(0).isModal())) { + assert (window.isModal()); + } + for (TWindow w: windows) { + w.setActive(false); + w.setZ(w.getZ() + 1); + } + windows.add(window); + window.setActive(true); + window.setZ(0); } - windows.add(window); - window.setActive(true); - window.setZ(0); } /** @@ -1248,29 +1256,31 @@ public class TApplication { return; } - Collections.sort(windows); - if (windows.get(0).isModal()) { - // Modal windows don't switch - return; - } + synchronized (windows) { + Collections.sort(windows); + if (windows.get(0).isModal()) { + // Modal windows don't switch + return; + } - for (TWindow window: windows) { - assert (!window.isModal()); - if (window.mouseWouldHit(mouse)) { - if (window == windows.get(0)) { - // Clicked on the same window, nothing to do + for (TWindow window: windows) { + assert (!window.isModal()); + if (window.mouseWouldHit(mouse)) { + if (window == windows.get(0)) { + // Clicked on the same window, nothing to do + return; + } + + // We will be switching to another window + assert (windows.get(0).getActive()); + assert (!window.getActive()); + windows.get(0).setActive(false); + windows.get(0).setZ(window.getZ()); + window.setZ(0); + window.setActive(true); + repaint = true; return; } - - // We will be switching to another window - assert (windows.get(0).getActive()); - assert (!window.getActive()); - windows.get(0).setActive(false); - windows.get(0).setZ(window.getZ()); - window.setZ(0); - window.setActive(true); - repaint = true; - return; } } @@ -1578,8 +1588,11 @@ public class TApplication { if (activeMenu != null) { return; } - for (TWindow window: windows) { - closeWindow(window); + + synchronized (windows) { + for (TWindow window: windows) { + closeWindow(window); + } } } @@ -1588,52 +1601,54 @@ public class TApplication { * almost the same results as Turbo Pascal 7.0's IDE. */ private void tileWindows() { - // Don't do anything if we are in the menu - if (activeMenu != null) { - return; - } - int z = windows.size(); - if (z == 0) { - return; - } - int a = 0; - int b = 0; - a = (int)(Math.sqrt(z)); - int c = 0; - while (c < a) { - b = (z - c) / a; - if (((a * b) + c) == z) { - break; + synchronized (windows) { + // Don't do anything if we are in the menu + if (activeMenu != null) { + return; } - c++; - } - assert (a > 0); - assert (b > 0); - assert (c < a); - int newWidth = (getScreen().getWidth() / a); - int newHeight1 = ((getScreen().getHeight() - 1) / b); - int newHeight2 = ((getScreen().getHeight() - 1) / (b + c)); - - List sorted = new LinkedList(windows); - Collections.sort(sorted); - Collections.reverse(sorted); - for (int i = 0; i < sorted.size(); i++) { - int logicalX = i / b; - int logicalY = i % b; - if (i >= ((a - 1) * b)) { - logicalX = a - 1; - logicalY = i - ((a - 1) * b); + int z = windows.size(); + if (z == 0) { + return; + } + int a = 0; + int b = 0; + a = (int)(Math.sqrt(z)); + int c = 0; + while (c < a) { + b = (z - c) / a; + if (((a * b) + c) == z) { + break; + } + c++; } + assert (a > 0); + assert (b > 0); + assert (c < a); + int newWidth = (getScreen().getWidth() / a); + int newHeight1 = ((getScreen().getHeight() - 1) / b); + int newHeight2 = ((getScreen().getHeight() - 1) / (b + c)); + + List sorted = new LinkedList(windows); + Collections.sort(sorted); + Collections.reverse(sorted); + for (int i = 0; i < sorted.size(); i++) { + int logicalX = i / b; + int logicalY = i % b; + if (i >= ((a - 1) * b)) { + logicalX = a - 1; + logicalY = i - ((a - 1) * b); + } - TWindow w = sorted.get(i); - w.setX(logicalX * newWidth); - w.setWidth(newWidth); - if (i >= ((a - 1) * b)) { - w.setY((logicalY * newHeight2) + 1); - w.setHeight(newHeight2); - } else { - w.setY((logicalY * newHeight1) + 1); - w.setHeight(newHeight1); + TWindow w = sorted.get(i); + w.setX(logicalX * newWidth); + w.setWidth(newWidth); + if (i >= ((a - 1) * b)) { + w.setY((logicalY * newHeight2) + 1); + w.setHeight(newHeight2); + } else { + w.setY((logicalY * newHeight1) + 1); + w.setHeight(newHeight1); + } } } } @@ -1642,25 +1657,27 @@ public class TApplication { * Re-layout the open windows as overlapping cascaded windows. */ private void cascadeWindows() { - // Don't do anything if we are in the menu - if (activeMenu != null) { - return; - } - int x = 0; - int y = 1; - List sorted = new LinkedList(windows); - Collections.sort(sorted); - Collections.reverse(sorted); - for (TWindow window: sorted) { - window.setX(x); - window.setY(y); - x++; - y++; - if (x > getScreen().getWidth()) { - x = 0; + synchronized (windows) { + // Don't do anything if we are in the menu + if (activeMenu != null) { + return; } - if (y >= getScreen().getHeight()) { - y = 1; + int x = 0; + int y = 1; + List sorted = new LinkedList(windows); + Collections.sort(sorted); + Collections.reverse(sorted); + for (TWindow window: sorted) { + window.setX(x); + window.setY(y); + x++; + y++; + if (x > getScreen().getWidth()) { + x = 0; + } + if (y >= getScreen().getHeight()) { + y = 1; + } } } } diff --git a/src/jexer/io/ECMA48Terminal.java b/src/jexer/io/ECMA48Terminal.java index 9e9ffe3..7721330 100644 --- a/src/jexer/io/ECMA48Terminal.java +++ b/src/jexer/io/ECMA48Terminal.java @@ -1437,7 +1437,7 @@ public final class ECMA48Terminal implements Runnable { readBuffer = new char[readBuffer.length * 2]; } - int rc = input.read(readBuffer, 0, n); + int rc = input.read(readBuffer, 0, readBuffer.length); // System.err.printf("read() %d", rc); System.err.flush(); if (rc == -1) { // This is EOF diff --git a/src/jexer/tterminal/ECMA48.java b/src/jexer/tterminal/ECMA48.java index 41a5f4d..66ee95e 100644 --- a/src/jexer/tterminal/ECMA48.java +++ b/src/jexer/tterminal/ECMA48.java @@ -249,8 +249,34 @@ public class ECMA48 implements Runnable { // Synchronize so we don't stomp on the reader thread. synchronized (this) { - // Tell the reader thread to stop looking at input. It will - // close the input stream as it exits. + // Close the input stream + switch (type) { + case VT100: + case VT102: + case VT220: + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + // SQUASH + } + inputStream = null; + } + break; + case XTERM: + if (input != null) { + try { + input.close(); + } catch (IOException e) { + // SQUASH + } + input = null; + inputStream = null; + } + break; + } + + // Tell the reader thread to stop looking at input. if (stopReaderThread == false) { stopReaderThread = true; try { @@ -294,7 +320,7 @@ public class ECMA48 implements Runnable { /** * When true, the reader thread is expected to exit. */ - private boolean stopReaderThread = false; + private volatile boolean stopReaderThread = false; /** * The reader thread. @@ -329,7 +355,7 @@ public class ECMA48 implements Runnable { /** * The scrollback buffer characters + attributes. */ - private List scrollback; + private volatile List scrollback; /** * Get the scrollback buffer. @@ -343,7 +369,7 @@ public class ECMA48 implements Runnable { /** * The raw display buffer characters + attributes. */ - private List display; + private volatile List display; /** * Get the display buffer. @@ -5441,77 +5467,56 @@ public class ECMA48 implements Runnable { while (!done && !stopReaderThread) { try { - // We assume that if inputStream has bytes available, then - // input won't block on read(). int n = inputStream.available(); - if (n > 0) { - // System.err.printf("available() %d\n", n); System.err.flush(); - if (utf8) { - if (readBufferUTF8.length < n) { - // The buffer wasn't big enough, make it huger - int newSize = Math.max(readBufferUTF8.length * 2, n); - - readBufferUTF8 = new char[newSize]; - } - } else { - if (readBuffer.length < n) { - // The buffer wasn't big enough, make it huger - int newSize = Math.max(readBuffer.length * 2, n); - readBuffer = new byte[newSize]; - } - } + // System.err.printf("available() %d\n", n); System.err.flush(); + if (utf8) { + if (readBufferUTF8.length < n) { + // The buffer wasn't big enough, make it huger + int newSizeHalf = Math.max(readBufferUTF8.length, n); - int rc = -1; - if (utf8) { - rc = input.read(readBufferUTF8, 0, n); - } else { - rc = inputStream.read(readBuffer, 0, n); + readBufferUTF8 = new char[newSizeHalf * 2]; } - // System.err.printf("read() %d\n", rc); System.err.flush(); - if (rc == -1) { - // 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) { - consume((char)ch); - } - } + } else { + if (readBuffer.length < n) { + // The buffer wasn't big enough, make it huger + int newSizeHalf = Math.max(readBuffer.length, n); + readBuffer = new byte[newSizeHalf * 2]; } + } + + int rc = -1; + if (utf8) { + rc = input.read(readBufferUTF8, 0, + readBufferUTF8.length); } else { - // Wait 10 millis for more data - Thread.sleep(10); + rc = inputStream.read(readBuffer, 0, + readBuffer.length); + } + // System.err.printf("read() %d\n", rc); System.err.flush(); + if (rc == -1) { + // 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) { + consume((char)ch); + } + } } // System.err.println("end while loop"); System.err.flush(); - } catch (InterruptedException e) { - // SQUASH } catch (IOException e) { e.printStackTrace(); done = true; } } // while ((done == false) && (stopReaderThread == false)) - // Close the input stream - try { - if (utf8) { - input.close(); - input = null; - inputStream = null; - } else { - inputStream.close(); - inputStream = null; - } - } catch (IOException e) { - e.printStackTrace(); - } - // Let the rest of the world know that I am done. stopReaderThread = true; -- 2.27.0