From 63bb94784f03cd743b18ca9a98d460708f69994d Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Fri, 1 Mar 2019 21:00:31 -0600 Subject: [PATCH] #38 multiple backend disconencts --- src/jexer/backend/ECMA48Terminal.java | 7 ++-- src/jexer/backend/GenericBackend.java | 12 +++++- src/jexer/backend/MultiBackend.java | 54 +++++++++++++++++++++++++-- src/jexer/backend/MultiScreen.java | 4 +- src/jexer/backend/SwingTerminal.java | 10 ++--- src/jexer/backend/TWindowBackend.java | 20 ++++++---- 6 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/jexer/backend/ECMA48Terminal.java b/src/jexer/backend/ECMA48Terminal.java index d10437c..6085554 100644 --- a/src/jexer/backend/ECMA48Terminal.java +++ b/src/jexer/backend/ECMA48Terminal.java @@ -44,7 +44,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.LinkedList; import jexer.TImage; import jexer.bits.Cell; @@ -1109,7 +1108,7 @@ public class ECMA48Terminal extends LogicalScreen reloadOptions(); // Spin up the input reader - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); readerThread = new Thread(this); readerThread.start(); @@ -1195,7 +1194,7 @@ public class ECMA48Terminal extends LogicalScreen reloadOptions(); // Spin up the input reader - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); readerThread = new Thread(this); readerThread.start(); @@ -1392,7 +1391,7 @@ public class ECMA48Terminal extends LogicalScreen // available() will often return > 1, so we need to read in chunks to // stay caught up. char [] readBuffer = new char[128]; - List events = new LinkedList(); + List events = new ArrayList(); while (!done && !stopReaderThread) { try { diff --git a/src/jexer/backend/GenericBackend.java b/src/jexer/backend/GenericBackend.java index 8d8fb37..ede3c0b 100644 --- a/src/jexer/backend/GenericBackend.java +++ b/src/jexer/backend/GenericBackend.java @@ -60,6 +60,16 @@ public abstract class GenericBackend implements Backend { */ protected TerminalReader terminal; + /** + * By default, GenericBackend adds a cmAbort after it sees + * cmBackendDisconnect, so that TApplication will exit when the user + * closes the Swing window or disconnects the ECMA48 streams. But + * MultiBackend wraps multiple Backends, and needs to decide when to send + * cmAbort differently. Setting this to false is how it manages that. + * Note package private access. + */ + boolean abortOnDisconnect = true; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -113,7 +123,7 @@ public abstract class GenericBackend implements Backend { // This default backend assumes a single user, and if that user // becomes disconnected we should terminate the application. - if (queue.size() > 0) { + if ((queue.size() > 0) && (abortOnDisconnect == true)) { TInputEvent event = queue.get(queue.size() - 1); if (event instanceof TCommandEvent) { TCommandEvent command = (TCommandEvent) event; diff --git a/src/jexer/backend/MultiBackend.java b/src/jexer/backend/MultiBackend.java index 08591ed..d01b944 100644 --- a/src/jexer/backend/MultiBackend.java +++ b/src/jexer/backend/MultiBackend.java @@ -28,10 +28,12 @@ */ package jexer.backend; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; +import jexer.event.TCommandEvent; import jexer.event.TInputEvent; +import static jexer.TCommand.*; /** * MultiBackend mirrors its I/O to several backends. @@ -50,7 +52,12 @@ public class MultiBackend implements Backend { /** * The list of backends to use. */ - private List backends = new LinkedList(); + private List backends = new ArrayList(); + + /** + * The SessionInfo to return. + */ + private SessionInfo sessionInfo; // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- @@ -69,6 +76,10 @@ public class MultiBackend implements Backend { } else { multiScreen = new MultiScreen(backend.getScreen()); } + if (backend instanceof GenericBackend) { + ((GenericBackend) backend).abortOnDisconnect = false; + } + sessionInfo = backend.getSessionInfo(); } // ------------------------------------------------------------------------ @@ -81,7 +92,7 @@ public class MultiBackend implements Backend { * @return the SessionInfo */ public SessionInfo getSessionInfo() { - return backends.get(0).getSessionInfo(); + return sessionInfo; } /** @@ -109,6 +120,9 @@ public class MultiBackend implements Backend { * @return if true, getEvents() has something to return to the application */ public boolean hasEvents() { + if (backends.size() == 0) { + return true; + } for (Backend backend: backends) { if (backend.hasEvents()) { return true; @@ -124,8 +138,37 @@ public class MultiBackend implements Backend { * @param queue list to append new events to */ public void getEvents(List queue) { + List backendsToRemove = null; for (Backend backend: backends) { - backend.getEvents(queue); + if (backend.hasEvents()) { + backend.getEvents(queue); + + // This default backend assumes a single user, and if that + // user becomes disconnected we should terminate the + // application. + if (queue.size() > 0) { + TInputEvent event = queue.get(queue.size() - 1); + if (event instanceof TCommandEvent) { + TCommandEvent command = (TCommandEvent) event; + if (command.equals(cmBackendDisconnect)) { + if (backendsToRemove == null) { + backendsToRemove = new ArrayList(); + } + backendsToRemove.add(backend); + } + } + } + } + } + if (backendsToRemove != null) { + for (Backend backend: backendsToRemove) { + multiScreen.removeScreen(backend.getScreen()); + backends.remove(backend); + backend.shutdown(); + } + } + if (backends.size() == 0) { + queue.add(new TCommandEvent(cmAbort)); } } @@ -187,6 +230,9 @@ public class MultiBackend implements Backend { } else { multiScreen.addScreen(backend.getScreen()); } + if (backend instanceof GenericBackend) { + ((GenericBackend) backend).abortOnDisconnect = false; + } } /** diff --git a/src/jexer/backend/MultiScreen.java b/src/jexer/backend/MultiScreen.java index 880ee18..b77872b 100644 --- a/src/jexer/backend/MultiScreen.java +++ b/src/jexer/backend/MultiScreen.java @@ -28,7 +28,7 @@ */ package jexer.backend; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; import jexer.bits.Cell; @@ -46,7 +46,7 @@ public class MultiScreen implements Screen { /** * The list of screens to use. */ - private List screens = new LinkedList(); + private List screens = new ArrayList(); // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- diff --git a/src/jexer/backend/SwingTerminal.java b/src/jexer/backend/SwingTerminal.java index 4efff3c..43afc16 100644 --- a/src/jexer/backend/SwingTerminal.java +++ b/src/jexer/backend/SwingTerminal.java @@ -51,8 +51,8 @@ import java.awt.event.WindowListener; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.InputStream; +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.swing.JComponent; @@ -411,7 +411,7 @@ public class SwingTerminal extends LogicalScreen mouse1 = false; mouse2 = false; mouse3 = false; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); // Add listeners to Swing. swing.addKeyListener(this); @@ -525,7 +525,7 @@ public class SwingTerminal extends LogicalScreen mouse1 = false; mouse2 = false; mouse3 = false; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); // Add listeners to Swing. swing.addKeyListener(this); @@ -1843,9 +1843,9 @@ public class SwingTerminal extends LogicalScreen * @param event window event received */ public void windowClosing(final WindowEvent event) { - // Drop a cmAbort and walk away + // Drop a cmBackendDisconnect and walk away synchronized (eventQueue) { - eventQueue.add(new TCommandEvent(cmAbort)); + eventQueue.add(new TCommandEvent(cmBackendDisconnect)); resetBlinkTimer(); } if (listener != null) { diff --git a/src/jexer/backend/TWindowBackend.java b/src/jexer/backend/TWindowBackend.java index ed701ad..3c1f832 100644 --- a/src/jexer/backend/TWindowBackend.java +++ b/src/jexer/backend/TWindowBackend.java @@ -28,15 +28,17 @@ */ package jexer.backend; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; +import jexer.TApplication; +import jexer.TWindow; +import jexer.event.TCommandEvent; import jexer.event.TInputEvent; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; -import jexer.TApplication; -import jexer.TWindow; +import static jexer.TCommand.*; /** * TWindowBackend uses a window in one TApplication to provide a backend for @@ -134,7 +136,7 @@ public class TWindowBackend extends TWindow implements Backend { super(application, title, width, height); this.listener = listener; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); sessionInfo = new TSessionInfo(width, height); otherScreen = new OtherScreen(this); otherScreen.setDimensions(width - 2, height - 2); @@ -160,7 +162,7 @@ public class TWindowBackend extends TWindow implements Backend { super(application, title, width, height, flags); this.listener = listener; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); sessionInfo = new TSessionInfo(width, height); otherScreen = new OtherScreen(this); otherScreen.setDimensions(width - 2, height - 2); @@ -187,7 +189,7 @@ public class TWindowBackend extends TWindow implements Backend { super(application, title, x, y, width, height); this.listener = listener; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); sessionInfo = new TSessionInfo(width, height); otherScreen = new OtherScreen(this); otherScreen.setDimensions(width - 2, height - 2); @@ -216,7 +218,7 @@ public class TWindowBackend extends TWindow implements Backend { super(application, title, x, y, width, height, flags); this.listener = listener; - eventQueue = new LinkedList(); + eventQueue = new ArrayList(); sessionInfo = new TSessionInfo(width, height); otherScreen = new OtherScreen(this); otherScreen.setDimensions(width - 2, height - 2); @@ -408,7 +410,9 @@ public class TWindowBackend extends TWindow implements Backend { */ @Override public void onClose() { - // TODO: send a screen disconnect + synchronized (eventQueue) { + eventQueue.add(new TCommandEvent(cmBackendDisconnect)); + } } // ------------------------------------------------------------------------ -- 2.27.0