JAL-1332 JAL-4298 JAL-3772 rejig the quit handler so we have a JVM-exit safe way... jims/bug/JAL-4298_java_console_causing_hang_at_startup
authorJames Procter <j.procter@dundee.ac.uk>
Sat, 21 Oct 2023 12:25:36 +0000 (13:25 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Sat, 21 Oct 2023 12:25:36 +0000 (13:25 +0100)
src/jalview/gui/Desktop.java

index 1cedf3b..35afb69 100644 (file)
@@ -1477,62 +1477,73 @@ public class Desktop extends jalview.jbgui.GDesktop
     desktopQuit(true, false);
   }
 
-  public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
-  {
-    final Runnable doDesktopQuit = () -> {
-      Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
-      Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
-      Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
-      storeLastKnownDimensions("", new Rectangle(getBounds().x,
-              getBounds().y, getWidth(), getHeight()));
+  /**
+   * close everything, stash window geometries, and shut down all associated threads/workers  
+   * @param dispose - sets the dispose on close flag - JVM may terminate when set
+   * @param terminateJvm - quit with prejudice - stops the JVM.
+   */
+  public void quitTheDesktop(boolean dispose, boolean terminateJvm) {
+    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+    Cache.setProperty("SCREENGEOMETRY_WIDTH", screen.width + "");
+    Cache.setProperty("SCREENGEOMETRY_HEIGHT", screen.height + "");
+    storeLastKnownDimensions("", new Rectangle(getBounds().x,
+            getBounds().y, getWidth(), getHeight()));
 
-      if (jconsole != null)
-      {
-        storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
-        jconsole.stopConsole();
-      }
+    if (jconsole != null)
+    {
+      storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
+      jconsole.stopConsole();
+    }
 
-      if (jvnews != null)
-      {
-        storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
-      }
+    if (jvnews != null)
+    {
+      storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
+    }
 
-      // Frames should all close automatically. Keeping external
-      // viewers open should already be decided by user.
-      closeAll_actionPerformed(null);
+    // Frames should all close automatically. Keeping external
+    // viewers open should already be decided by user.
+    closeAll_actionPerformed(null);
 
-      // check for aborted quit
-      if (QuitHandler.quitCancelled())
-      {
-        jalview.bin.Console.debug("Desktop aborting quit");
-        return;
-      }
+    if (dialogExecutor != null)
+    {
+      dialogExecutor.shutdownNow();
+    }
 
-      if (dialogExecutor != null)
-      {
-        dialogExecutor.shutdownNow();
-      }
+    if (groovyConsole != null)
+    {
+      // suppress a possible repeat prompt to save script
+      groovyConsole.setDirty(false);
+      groovyConsole.exit();
+    }
 
-      if (groovyConsole != null)
-      {
-        // suppress a possible repeat prompt to save script
-        groovyConsole.setDirty(false);
-        groovyConsole.exit();
-      }
+    if (terminateJvm)
+    {
+      // note that shutdown hook will not be run
+      jalview.bin.Console.debug("Force Quit selected by user");
+      Runtime.getRuntime().halt(0);
+    }
 
-      if (QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT)
-      {
-        // note that shutdown hook will not be run
-        jalview.bin.Console.debug("Force Quit selected by user");
-        Runtime.getRuntime().halt(0);
-      }
+    jalview.bin.Console.debug("Quit selected by user");
+    if (dispose)
+    {
+      instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+      // instance.dispose();
+    }
+  }
+  public QuitHandler.QResponse desktopQuit(boolean ui, boolean disposeFlag)
+  {
+    final Runnable doDesktopQuit = () -> {
 
-      jalview.bin.Console.debug("Quit selected by user");
-      if (disposeFlag)
+      // FIRST !!  check for aborted quit
+      if (QuitHandler.quitCancelled())
       {
-        instance.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-        // instance.dispose();
+        jalview.bin.Console.debug("Quit was cancelled - Desktop aborting quit");
+        return;
       }
+      
+      // Proceed with quitting
+      quitTheDesktop(disposeFlag, QuitHandler.gotQuitResponse() == QResponse.FORCE_QUIT);
+      // and exit the JVM
       instance.quit();
     };
 
@@ -1541,7 +1552,14 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   /**
-   * Don't call this directly, use desktopQuit() above. Exits the program.
+   * Exits the program and the JVM. 
+   * 
+   * Don't call this directly
+   * 
+   * - use desktopQuit() above to tidy up first.
+   * 
+   * - use closeDesktop() to shutdown Jalview without shutting down the JVM 
+   * 
    */
   @Override
   public void quit()
@@ -3700,32 +3718,34 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   /**
-   * closes the current instance window, disposes and forgets about it.
+   * closes the current instance window, but leaves the JVM running.
+   * Bypasses any shutdown prompts, but does not set window dispose on close in case JVM terminates.
    */
   public static void closeDesktop()
   {
     if (Desktop.instance != null)
     {
-      Desktop.instance.closeAll_actionPerformed(null);
-      Desktop.instance.setVisible(false);
       Desktop us = Desktop.instance;
-      Desktop.instance = null;
+      Desktop.instance.quitTheDesktop(false, false);
       // call dispose in a separate thread - try to avoid indirect deadlocks
-      new Thread(new Runnable()
+      if (us != null)
       {
-        @Override
-        public void run()
+        new Thread(new Runnable()
         {
-          ExecutorService dex = us.dialogExecutor;
-          if (dex != null)
+          @Override
+          public void run()
           {
-            dex.shutdownNow();
-            us.dialogExecutor = null;
-            us.block.drainPermits();
+            ExecutorService dex = us.dialogExecutor;
+            if (dex != null)
+            {
+              dex.shutdownNow();
+              us.dialogExecutor = null;
+              us.block.drainPermits();
+            }
+            us.dispose();
           }
-          us.dispose();
-        }
-      }).start();
+        }).start();
+      }
     }
   }