#38 multiple backend disconencts
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 2 Mar 2019 03:00:31 +0000 (21:00 -0600)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 2 Mar 2019 03:00:31 +0000 (21:00 -0600)
src/jexer/backend/ECMA48Terminal.java
src/jexer/backend/GenericBackend.java
src/jexer/backend/MultiBackend.java
src/jexer/backend/MultiScreen.java
src/jexer/backend/SwingTerminal.java
src/jexer/backend/TWindowBackend.java

index d10437c1f49dd377bce18ac786b9ecfae3555357..6085554904320675139608a67329e0bbe33428fe 100644 (file)
@@ -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<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         readerThread = new Thread(this);
         readerThread.start();
 
@@ -1195,7 +1194,7 @@ public class ECMA48Terminal extends LogicalScreen
         reloadOptions();
 
         // Spin up the input reader
-        eventQueue = new LinkedList<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         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<TInputEvent> events = new LinkedList<TInputEvent>();
+        List<TInputEvent> events = new ArrayList<TInputEvent>();
 
         while (!done && !stopReaderThread) {
             try {
index 8d8fb3752243161eed12545ce3ebba9c5cfd4ba2..ede3c0bff4365743f1d8c38d3c4b130f1cdc01f0 100644 (file)
@@ -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;
index 08591ed44b8b90fc651978581ab052d68ce0d63e..d01b9442c0526cc9ce2a67af0be5e8f1a2a514c7 100644 (file)
  */
 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<Backend> backends = new LinkedList<Backend>();
+    private List<Backend> backends = new ArrayList<Backend>();
+
+    /**
+     * 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<TInputEvent> queue) {
+        List<Backend> 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<Backend>();
+                            }
+                            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;
+        }
     }
 
     /**
index 880ee1888300d12ae936ed2106c927b311cdc5a0..b77872bba5f6eb617c70dace855efe9c9501bb2c 100644 (file)
@@ -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<Screen> screens = new LinkedList<Screen>();
+    private List<Screen> screens = new ArrayList<Screen>();
 
     // ------------------------------------------------------------------------
     // Constructors -----------------------------------------------------------
index 4efff3c22e0b5538cf32c892f9970f5797ed99ab..43afc1615a848141e1937abacc4884d46386a71e 100644 (file)
@@ -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<TInputEvent>();
+        eventQueue       = new ArrayList<TInputEvent>();
 
         // 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<TInputEvent>();
+        eventQueue       = new ArrayList<TInputEvent>();
 
         // 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) {
index ed701ad0076dc93d2a9a54f66254f70d2bd0204f..3c1f832cfefdb8ba6cc2a0c10204abc2fec92306 100644 (file)
  */
 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<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         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<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         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<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         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<TInputEvent>();
+        eventQueue = new ArrayList<TInputEvent>();
         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));
+        }
     }
 
     // ------------------------------------------------------------------------