Merge commit 'alpha/update_2_12_for_2_11_2_series_merge^2' into HEAD
[jalview.git] / src / jalview / gui / Desktop.java
index 0f80dd5..f35a6a8 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.gui;
 
 import java.util.Locale;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -65,8 +64,11 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Vector;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 import java.util.concurrent.Semaphore;
 
 import javax.swing.AbstractAction;
@@ -100,6 +102,9 @@ import org.stackoverflowusers.file.WindowsShortcut;
 
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.api.StructureSelectionManagerProvider;
+import jalview.bin.ApplicationSingletonProvider;
+import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.gui.ImageExporter.ImageWriterI;
@@ -114,6 +119,7 @@ import jalview.io.FormatAdapter;
 import jalview.io.IdentifyFile;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
+import jalview.jbgui.GDesktop;
 import jalview.jbgui.GSplitFrame;
 import jalview.jbgui.GStructureViewer;
 import jalview.project.Jalview2XML;
@@ -127,6 +133,7 @@ import jalview.util.Platform;
 import jalview.util.ShortcutKeyMaskExWrapper;
 import jalview.util.UrlConstants;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.WSDiscovererI;
 import jalview.ws.params.ParamManager;
 import jalview.ws.utils.UrlDownloadClient;
 
@@ -137,8 +144,12 @@ import jalview.ws.utils.UrlDownloadClient;
  * @author $author$
  * @version $Revision: 1.155 $
  */
-public class Desktop extends jalview.jbgui.GDesktop
-    implements DropTargetListener, ClipboardOwner, IProgressIndicator, jalview.api.StructureSelectionManagerProvider {
+@SuppressWarnings("serial")
+public class Desktop extends GDesktop
+        implements DropTargetListener, ClipboardOwner, IProgressIndicator,
+        StructureSelectionManagerProvider, ApplicationSingletonI
+
+{
   private static final String CITATION;
   static {
     URL bg_logo_url = ChannelProperties.getImageURL("bg_logo." + String.valueOf(SplashScreen.logoSize));
@@ -177,10 +188,10 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
 
+  @SuppressWarnings("deprecation")
   private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
 
   public static boolean nosplash = false;
-
   /**
    * news reader - null if it was never started.
    */
@@ -192,7 +203,10 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @param listener
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
    */
-  public void addJalviewPropertyChangeListener(PropertyChangeListener listener) {
+  @Deprecated
+  public void addJalviewPropertyChangeListener(
+          PropertyChangeListener listener)
+  {
     changeSupport.addJalviewPropertyChangeListener(listener);
   }
 
@@ -202,7 +216,10 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
-  public void addJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
+  @Deprecated
+  public void addJalviewPropertyChangeListener(String propertyName,
+          PropertyChangeListener listener)
+  {
     changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
   }
 
@@ -212,128 +229,172 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
    *      java.beans.PropertyChangeListener)
    */
-  public void removeJalviewPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
-    changeSupport.removeJalviewPropertyChangeListener(propertyName, listener);
+  @Deprecated
+  public void removeJalviewPropertyChangeListener(String propertyName,
+          PropertyChangeListener listener)
+  {
+    changeSupport.removeJalviewPropertyChangeListener(propertyName,
+            listener);
   }
 
-  /** Singleton Desktop instance */
-  public static Desktop instance;
+  private MyDesktopPane desktopPane;
 
-  public static MyDesktopPane desktop;
+  public static MyDesktopPane getDesktopPane()
+  {
+    Desktop desktop = getInstance();
+    return desktop == null ? null : desktop.desktopPane;
+  }
 
-  public static MyDesktopPane getDesktop() {
-    // BH 2018 could use currentThread() here as a reference to a
-    // Hashtable<Thread, MyDesktopPane> in JavaScript
-    return desktop;
+  /**
+   * Answers an 'application scope' singleton instance of this class. Separate
+   * SwingJS 'applets' running in the same browser page will each have a
+   * distinct instance of Desktop.
+   * 
+   * @return
+   */
+  public static Desktop getInstance()
+  {
+    return Jalview.isHeadlessMode() ? null
+            : (Desktop) ApplicationSingletonProvider
+                    .getInstance(Desktop.class);
   }
 
-  static int openFrameCount = 0;
+  public static StructureSelectionManager getStructureSelectionManager()
+  {
+    return StructureSelectionManager
+            .getStructureSelectionManager(getInstance());
+  }
+
+  int openFrameCount = 0;
 
-  static final int xOffset = 30;
+  final int xOffset = 30;
 
-  static final int yOffset = 30;
+  final int yOffset = 30;
 
-  public static jalview.ws.jws1.Discoverer discoverer;
+  public jalview.ws.jws1.Discoverer discoverer;
 
-  public static Object[] jalviewClipboard;
+  public Object[] jalviewClipboard;
 
-  public static boolean internalCopy = false;
+  public boolean internalCopy = false;
 
-  static int fileLoadingCount = 0;
+  int fileLoadingCount = 0;
 
-  class MyDesktopManager implements DesktopManager {
+  class MyDesktopManager implements DesktopManager
+  {
 
     private DesktopManager delegate;
 
-    public MyDesktopManager(DesktopManager delegate) {
+    public MyDesktopManager(DesktopManager delegate)
+    {
       this.delegate = delegate;
     }
 
     @Override
-    public void activateFrame(JInternalFrame f) {
-      try {
+    public void activateFrame(JInternalFrame f)
+    {
+      try
+      {
         delegate.activateFrame(f);
-      } catch (NullPointerException npe) {
+      } catch (NullPointerException npe)
+      {
         Point p = getMousePosition();
-        instance.showPasteMenu(p.x, p.y);
+        showPasteMenu(p.x, p.y);
       }
     }
 
     @Override
-    public void beginDraggingFrame(JComponent f) {
+    public void beginDraggingFrame(JComponent f)
+    {
       delegate.beginDraggingFrame(f);
     }
 
     @Override
-    public void beginResizingFrame(JComponent f, int direction) {
+    public void beginResizingFrame(JComponent f, int direction)
+    {
       delegate.beginResizingFrame(f, direction);
     }
 
     @Override
-    public void closeFrame(JInternalFrame f) {
+    public void closeFrame(JInternalFrame f)
+    {
       delegate.closeFrame(f);
     }
 
     @Override
-    public void deactivateFrame(JInternalFrame f) {
+    public void deactivateFrame(JInternalFrame f)
+    {
       delegate.deactivateFrame(f);
     }
 
     @Override
-    public void deiconifyFrame(JInternalFrame f) {
+    public void deiconifyFrame(JInternalFrame f)
+    {
       delegate.deiconifyFrame(f);
     }
 
     @Override
-    public void dragFrame(JComponent f, int newX, int newY) {
-      if (newY < 0) {
+    public void dragFrame(JComponent f, int newX, int newY)
+    {
+      if (newY < 0)
+      {
         newY = 0;
       }
       delegate.dragFrame(f, newX, newY);
     }
 
     @Override
-    public void endDraggingFrame(JComponent f) {
+    public void endDraggingFrame(JComponent f)
+    {
       delegate.endDraggingFrame(f);
-      desktop.repaint();
+      desktopPane.repaint();
     }
 
     @Override
-    public void endResizingFrame(JComponent f) {
+    public void endResizingFrame(JComponent f)
+    {
       delegate.endResizingFrame(f);
-      desktop.repaint();
+      desktopPane.repaint();
     }
 
     @Override
-    public void iconifyFrame(JInternalFrame f) {
+    public void iconifyFrame(JInternalFrame f)
+    {
       delegate.iconifyFrame(f);
     }
 
     @Override
-    public void maximizeFrame(JInternalFrame f) {
+    public void maximizeFrame(JInternalFrame f)
+    {
       delegate.maximizeFrame(f);
     }
 
     @Override
-    public void minimizeFrame(JInternalFrame f) {
+    public void minimizeFrame(JInternalFrame f)
+    {
       delegate.minimizeFrame(f);
     }
 
     @Override
-    public void openFrame(JInternalFrame f) {
+    public void openFrame(JInternalFrame f)
+    {
       delegate.openFrame(f);
     }
 
     @Override
-    public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
-      if (newY < 0) {
+    public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
+            int newHeight)
+    {
+      if (newY < 0)
+      {
         newY = 0;
       }
       delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
     }
 
     @Override
-    public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
+    public void setBoundsForFrame(JComponent f, int newX, int newY,
+            int newWidth, int newHeight)
+    {
       delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
     }
 
@@ -342,17 +403,22 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   /**
-   * Creates a new Desktop object.
+   * Private constructor enforces singleton pattern. It is called by reflection
+   * from ApplicationSingletonProvider.getInstance().
    */
-  public Desktop() {
+  private Desktop()
+  {
     super();
-    /**
-     * A note to implementors. It is ESSENTIAL that any activities that might block
-     * are spawned off as threads rather than waited for during this constructor.
-     */
-    instance = this;
+    Cache.initLogger();
+    try
+    {
+      /**
+       * A note to implementors. It is ESSENTIAL that any activities that might
+       * block are spawned off as threads rather than waited for during this
+       * constructor.
+       */
 
-    doConfigureStructurePrefs();
+      doConfigureStructurePrefs();
     setTitle(ChannelProperties.getProperty("app_name") + " " + Cache.getProperty("VERSION"));
 
     /**
@@ -414,124 +480,156 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
     });
 
-    boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", false);
+      boolean selmemusage = Cache.getDefault("SHOW_MEMUSAGE", false);
 
-    boolean showjconsole = Cache.getDefault("SHOW_JAVA_CONSOLE", false);
-    desktop = new MyDesktopPane(selmemusage);
+      boolean showjconsole = Cache.getDefault("SHOW_JAVA_CONSOLE", false);
+      desktopPane = new MyDesktopPane(selmemusage);
 
-    showMemusage.setSelected(selmemusage);
-    desktop.setBackground(Color.white);
+      showMemusage.setSelected(selmemusage);
+      desktopPane.setBackground(Color.white);
 
-    getContentPane().setLayout(new BorderLayout());
-    // alternate config - have scrollbars - see notes in JAL-153
-    // JScrollPane sp = new JScrollPane();
-    // sp.getViewport().setView(desktop);
-    // getContentPane().add(sp, BorderLayout.CENTER);
+      getContentPane().setLayout(new BorderLayout());
+      // alternate config - have scrollbars - see notes in JAL-153
+      // JScrollPane sp = new JScrollPane();
+      // sp.getViewport().setView(desktop);
+      // getContentPane().add(sp, BorderLayout.CENTER);
 
-    // BH 2018 - just an experiment to try unclipped JInternalFrames.
-    if (Platform.isJS()) {
-      getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
-    }
+      // BH 2018 - just an experiment to try unclipped JInternalFrames.
+      if (Platform.isJS())
+      {
+        getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
+      }
 
-    getContentPane().add(desktop, BorderLayout.CENTER);
-    desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
+      getContentPane().add(desktopPane, BorderLayout.CENTER);
+      desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
 
-    // This line prevents Windows Look&Feel resizing all new windows to maximum
-    // if previous window was maximised
-    desktop.setDesktopManager(new MyDesktopManager((Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
-        : Platform.isAMacAndNotJS() ? new AquaInternalFrameManager(desktop.getDesktopManager())
-            : desktop.getDesktopManager())));
 
-    Rectangle dims = getLastKnownDimensions("");
-    if (dims != null) {
-      setBounds(dims);
-    } else {
-      Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-      int xPos = Math.max(5, (screenSize.width - 900) / 2);
-      int yPos = Math.max(5, (screenSize.height - 650) / 2);
-      setBounds(xPos, yPos, 900, 650);
-    }
+      // This line prevents Windows Look&Feel resizing all new windows to
+      // maximum
+      // if previous window was maximised
+      desktopPane.setDesktopManager(new MyDesktopManager(
+              (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
+                      : Platform.isAMacAndNotJS()
+                              ? new AquaInternalFrameManager(
+                                      desktopPane.getDesktopManager())
+                              : desktopPane.getDesktopManager())));
 
-    if (!Platform.isJS())
-    /**
-     * Java only
-     * 
-     * @j2sIgnore
-     */
-    {
-      jconsole = new Console(this, showjconsole);
-      jconsole.setHeader(Cache.getVersionDetailsForConsole());
-      showConsole(showjconsole);
+      Rectangle dims = getLastKnownDimensions("");
+      if (dims != null)
+      {
+        setBounds(dims);
+      }
+      else
+      {
+        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+        int xPos = Math.max(5, (screenSize.width - 900) / 2);
+        int yPos = Math.max(5, (screenSize.height - 650) / 2);
+        setBounds(xPos, yPos, 900, 650);
+      }
 
-      showNews.setVisible(false);
+      if (!Platform.isJS())
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
+      {
+        jconsole = new Console(this, showjconsole);
+        jconsole.setHeader(Cache.getVersionDetailsForConsole());
+        showConsole(showjconsole);
 
-      experimentalFeatures.setSelected(showExperimental());
+        showNews.setVisible(false); // not sure if we should only do this for interactive session?
 
-      getIdentifiersOrgData();
+        experimentalFeatures.setSelected(showExperimental());
 
-      checkURLLinks();
+        getIdentifiersOrgData();
 
-      // Spawn a thread that shows the splashscreen
-      if (!nosplash) {
-        SwingUtilities.invokeLater(new Runnable() {
-          @Override
-          public void run() {
-            new SplashScreen(true);
+        if (Jalview.isInteractive())
+        {
+          // disabled for SeqCanvasTest
+          checkURLLinks();
+
+          // Spawn a thread that shows the splashscreen
+          if (!nosplash) {
+          SwingUtilities.invokeLater(new Runnable()
+           {
+             @Override
+             public void run()
+             {
+               new SplashScreen(true);
+             }
+           });
           }
-        });
-      }
 
-      // Thread off a new instance of the file chooser - this reduces the time
-      // it
-      // takes to open it later on.
-      new Thread(new Runnable() {
-        @Override
-        public void run() {
-          Cache.log.debug("Filechooser init thread started.");
-          String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-          JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
-          Cache.log.debug("Filechooser init thread finished.");
+          // Thread off a new instance of the file chooser - this reduces the
+          // time
+          // it
+          // takes to open it later on.
+          new Thread(new Runnable()
+          {
+            @Override
+            public void run()
+            {
+              Cache.log.debug("Filechooser init thread started.");
+              String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
+              JalviewFileChooser.forRead(
+                      Cache.getProperty("LAST_DIRECTORY"), fileFormat);
+              Cache.log.debug("Filechooser init thread finished.");
+            }
+          }).start();
+          // Add the service change listener
+          changeSupport.addJalviewPropertyChangeListener("services",
+                  new PropertyChangeListener()
+                  {
+
+                    @Override
+                    public void propertyChange(PropertyChangeEvent evt)
+                    {
+                      Cache.log.debug("Firing service changed event for "
+                              + evt.getNewValue());
+                      JalviewServicesChanged(evt);
+                    }
+                  });
         }
-      }).start();
-      // Add the service change listener
-      changeSupport.addJalviewPropertyChangeListener("services", new PropertyChangeListener() {
+      }
 
+      this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this));
+
+      this.addWindowListener(new WindowAdapter()
+      {
         @Override
-        public void propertyChange(PropertyChangeEvent evt) {
-          Cache.log.debug("Firing service changed event for " + evt.getNewValue());
-          JalviewServicesChanged(evt);
+        public void windowClosing(WindowEvent evt)
+        {
+          quit();
         }
       });
-    }
-
-    this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
 
-    this.addWindowListener(new WindowAdapter() {
-      @Override
-      public void windowClosing(WindowEvent evt) {
-        quit();
-      }
-    });
-
-    MouseAdapter ma;
-    this.addMouseListener(ma = new MouseAdapter() {
-      @Override
-      public void mousePressed(MouseEvent evt) {
-        if (evt.isPopupTrigger()) // Mac
+      MouseAdapter ma;
+      this.addMouseListener(ma = new MouseAdapter()
+      {
+        @Override
+        public void mousePressed(MouseEvent evt)
         {
-          showPasteMenu(evt.getX(), evt.getY());
+          if (evt.isPopupTrigger()) // Mac
+          {
+            showPasteMenu(evt.getX(), evt.getY());
+          }
         }
-      }
-
-      @Override
-      public void mouseReleased(MouseEvent evt) {
-        if (evt.isPopupTrigger()) // Windows
+        @Override
+        public void mouseReleased(MouseEvent evt)
         {
-          showPasteMenu(evt.getX(), evt.getY());
+          if (evt.isPopupTrigger()) // Windows
+          {
+            showPasteMenu(evt.getX(), evt.getY());
+          }
         }
-      }
-    });
-    desktop.addMouseListener(ma);
+      });
+      desktopPane.addMouseListener(ma);
+    } catch (Throwable t)
+    {
+      t.printStackTrace();
+    }
+
   }
 
   /**
@@ -540,12 +638,15 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return
    */
-  public boolean showExperimental() {
-    String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES, Boolean.FALSE.toString());
+  public boolean showExperimental()
+  {
+    String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
+            Boolean.FALSE.toString());
     return Boolean.valueOf(experimental).booleanValue();
   }
 
-  public void doConfigureStructurePrefs() {
+  public void doConfigureStructurePrefs()
+  {
     // configure services
     StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager(this);
     if (Cache.getDefault(Preferences.ADD_SS_ANN, true)) {
@@ -596,17 +697,22 @@ public class Desktop extends jalview.jbgui.GDesktop
     showNews(showNews.isSelected());
   }
 
-  void showNews(boolean visible) {
+  void showNews(boolean visible)
+  {
     Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
     showNews.setSelected(visible);
-    if (visible && !jvnews.isVisible()) {
-      new Thread(new Runnable() {
+    if (visible && !jvnews.isVisible())
+    {
+      new Thread(new Runnable()
+      {
         @Override
-        public void run() {
+        public void run()
+        {
           long now = System.currentTimeMillis();
-          Desktop.instance.setProgressBar(MessageManager.getString("status.refreshing_news"), now);
+          setProgressBar(MessageManager.getString("status.refreshing_news"),
+                  now);
           jvnews.refreshNews();
-          Desktop.instance.setProgressBar(null, now);
+          setProgressBar(null, now);
           jvnews.showNews();
         }
       }).start();
@@ -616,12 +722,13 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * recover the last known dimensions for a jalview window
    * 
-   * @param windowName - empty string is desktop, all other windows have unique
-   *                   prefix
+   * @param windowName
+   *          - empty string is desktop, all other windows have unique prefix
    * @return null or last known dimensions scaled to current geometry (if last
    *         window geom was known)
    */
-  Rectangle getLastKnownDimensions(String windowName) {
+  Rectangle getLastKnownDimensions(String windowName)
+  {
     // TODO: lock aspect ratio for scaling desktop Bug #0058199
     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
     String x = Cache.getProperty(windowName + "SCREEN_X");
@@ -659,12 +766,16 @@ public class Desktop extends jalview.jbgui.GDesktop
     return null;
   }
 
-  void showPasteMenu(int x, int y) {
+  void showPasteMenu(int x, int y)
+  {
     JPopupMenu popup = new JPopupMenu();
-    JMenuItem item = new JMenuItem(MessageManager.getString("label.paste_new_window"));
-    item.addActionListener(new ActionListener() {
+    JMenuItem item = new JMenuItem(
+            MessageManager.getString("label.paste_new_window"));
+    item.addActionListener(new ActionListener()
+    {
       @Override
-      public void actionPerformed(ActionEvent evt) {
+      public void actionPerformed(ActionEvent evt)
+      {
         paste();
       }
     });
@@ -673,79 +784,81 @@ public class Desktop extends jalview.jbgui.GDesktop
     popup.show(this, x, y);
   }
 
-  public void paste() {
-    try {
+  public void paste()
+  {
+    try
+    {
       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
       Transferable contents = c.getContents(this);
 
-      if (contents != null) {
-        String file = (String) contents.getTransferData(DataFlavor.stringFlavor);
+      if (contents != null)
+      {
+        String file = (String) contents
+                .getTransferData(DataFlavor.stringFlavor);
 
-        FileFormatI format = new IdentifyFile().identify(file, DataSourceType.PASTE);
+        FileFormatI format = new IdentifyFile().identify(file,
+                DataSourceType.PASTE);
 
         new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
 
       }
-    } catch (Exception ex) {
-      System.out.println("Unable to paste alignment from system clipboard:\n" + ex);
+    } catch (Exception ex)
+    {
+      System.out.println(
+              "Unable to paste alignment from system clipboard:\n" + ex);
     }
   }
 
-  /**
-   * Adds and opens the given frame to the desktop
-   * 
-   * @param frame Frame to show
-   * @param title Visible Title
-   * @param w     width
-   * @param h     height
-   */
-  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, int w, int h) {
-    addInternalFrame(frame, title, true, w, h, true, false);
-  }
 
-  /**
-   * Add an internal frame to the Jalview desktop
-   * 
-   * @param frame       Frame to show
-   * @param title       Visible Title
-   * @param makeVisible When true, display frame immediately, otherwise, caller
-   *                    must call setVisible themselves.
-   * @param w           width
-   * @param h           height
-   */
-  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, boolean makeVisible, int w,
-      int h) {
-    addInternalFrame(frame, title, makeVisible, w, h, true, false);
-  }
 
   /**
-   * Add an internal frame to the Jalview desktop and make it visible
+   * Adds and opens the given frame to the desktop that is visible, allowed to
+   * resize, and has a 300px minimum width.
    * 
-   * @param frame     Frame to show
-   * @param title     Visible Title
-   * @param w         width
-   * @param h         height
-   * @param resizable Allow resize
-   */
-  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, int w, int h,
-      boolean resizable) {
-    addInternalFrame(frame, title, true, w, h, resizable, false);
+   * @param frame
+   *          Frame to show
+   * @param title
+   *          Visible Title
+   * @param w
+   *          width
+   * @param h
+   *          height
+   */
+  public static synchronized void addInternalFrame(
+          final JInternalFrame frame, String title, int w, int h)
+  {
+    // 58 classes
+    
+    addInternalFrame(frame, title, Desktop.FRAME_MAKE_VISIBLE, w, h, 
+            FRAME_ALLOW_RESIZE, FRAME_SET_MIN_SIZE_300);
   }
 
   /**
-   * Add an internal frame to the Jalview desktop
+   * Add an internal frame to the Jalview desktop that may optionally be
+   * visible, resizable, and allowed to be any size
    * 
-   * @param frame         Frame to show
-   * @param title         Visible Title
-   * @param makeVisible   When true, display frame immediately, otherwise, caller
-   *                      must call setVisible themselves.
-   * @param w             width
-   * @param h             height
-   * @param resizable     Allow resize
-   * @param ignoreMinSize Do not set the default minimum size for frame
-   */
-  public static synchronized void addInternalFrame(final JInternalFrame frame, String title, boolean makeVisible, int w,
-      int h, boolean resizable, boolean ignoreMinSize) {
+   * @param frame
+   *          Frame to show
+   * @param title
+   *          Visible Title
+   * @param makeVisible
+   *          When true, display frame immediately, otherwise, caller must call
+   *          setVisible themselves.
+   * @param w
+   *          width
+   * @param h
+   *          height
+   * @param resizable
+   *          Allow resize
+   * @param ignoreMinSize
+   *          Do not set the default minimum size for frame
+   */
+  public static synchronized void addInternalFrame(
+          final JInternalFrame frame, String title, boolean makeVisible,
+          int w, int h, boolean resizable, boolean ignoreMinSize)
+  {
+    // 15 classes call this method directly.
+    
 
     // TODO: allow callers to determine X and Y position of frame (eg. via
     // bounds object).
@@ -753,29 +866,57 @@ public class Desktop extends jalview.jbgui.GDesktop
     // the current window title
 
     frame.setTitle(title);
-    if (frame.getWidth() < 1 || frame.getHeight() < 1) {
+    if (frame.getWidth() < 1 || frame.getHeight() < 1)
+    {
       frame.setSize(w, h);
     }
-    // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
-    // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
-    // IF JALVIEW IS RUNNING HEADLESS
-    // ///////////////////////////////////////////////
-    if (instance == null || (System.getProperty("java.awt.headless") != null
-        && System.getProperty("java.awt.headless").equals("true"))) {
-      return;
-    }
+    if (getInstance() != null)
+      getInstance().addFrame(frame, makeVisible, resizable,
+            ignoreMinSize);
+  }
+
+  // These can now by put into a single int flag, if desired:
+  
+  public final static boolean FRAME_MAKE_VISIBLE = true;
+
+  public final static boolean FRAME_NOT_VISIBLE = false;
+
+  public final static boolean FRAME_ALLOW_RESIZE = true;
+
+  public final static boolean FRAME_NOT_RESIZABLE = false;
+
+  public final static boolean FRAME_ALLOW_ANY_SIZE = true;
+
+  public final static boolean FRAME_SET_MIN_SIZE_300 = false;
+  
+  private void addFrame(JInternalFrame frame,
+          boolean makeVisible, boolean resizable,
+          boolean ignoreMinSize)
+  {
 
     openFrameCount++;
 
-    if (!ignoreMinSize) {
-      frame.setMinimumSize(new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
+    
+    boolean isEmbedded = (Platform.getEmbeddedAttribute(frame, "id") != null);
+    boolean hasEmbeddedSize = (Platform.getDimIfEmbedded(frame, -1, -1) != null);
+    // Web page embedding allows us to ignore minimum size
+    ignoreMinSize |= hasEmbeddedSize;
+    
+    if (!ignoreMinSize)
+    {
 
       // Set default dimension for Alignment Frame window.
       // The Alignment Frame window could be added from a number of places,
       // hence,
       // I did this here in order not to miss out on any Alignment frame.
-      if (frame instanceof AlignFrame) {
-        frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH, ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
+      if (frame instanceof AlignFrame)
+      {
+        frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
+                ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
+      } else {
+        frame.setMinimumSize(
+                new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
+        
       }
     }
 
@@ -786,21 +927,27 @@ public class Desktop extends jalview.jbgui.GDesktop
     frame.setIconifiable(resizable);
     frame.setOpaque(Platform.isJS());
 
-    if (frame.getX() < 1 && frame.getY() < 1) {
-      frame.setLocation(xOffset * openFrameCount, yOffset * ((openFrameCount - 1) % 10) + yOffset);
+    if (!isEmbedded && frame.getX() < 1 && frame.getY() < 1)
+    {
+      frame.setLocation(xOffset * openFrameCount,
+              yOffset * ((openFrameCount - 1) % 10) + yOffset);
     }
 
     /*
-     * add an entry for the new frame in the Window menu (and remove it when the
-     * frame is closed)
+     * add an entry for the new frame in the Window menu 
+     * (and remove it when the frame is closed)
      */
-    final JMenuItem menuItem = new JMenuItem(title);
-    frame.addInternalFrameListener(new InternalFrameAdapter() {
+    final JMenuItem menuItem = new JMenuItem(frame.getTitle());
+    frame.addInternalFrameListener(new InternalFrameAdapter()
+    {
       @Override
-      public void internalFrameActivated(InternalFrameEvent evt) {
-        JInternalFrame itf = desktop.getSelectedFrame();
-        if (itf != null) {
-          if (itf instanceof AlignFrame) {
+      public void internalFrameActivated(InternalFrameEvent evt)
+      {
+        JInternalFrame itf = getDesktopPane().getSelectedFrame();
+        if (itf != null)
+        {
+          if (itf instanceof AlignFrame)
+          {
             Jalview.setCurrentAlignFrame((AlignFrame) itf);
           }
           itf.requestFocus();
@@ -808,67 +955,80 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
 
       @Override
-      public void internalFrameClosed(InternalFrameEvent evt) {
+      public void internalFrameClosed(InternalFrameEvent evt)
+      {
         PaintRefresher.RemoveComponent(frame);
 
         /*
-         * defensive check to prevent frames being added half off the window
+         * defensive check to prevent frames being
+         * added half off the window
          */
-        if (openFrameCount > 0) {
+        if (openFrameCount > 0)
+        {
           openFrameCount--;
         }
 
         /*
          * ensure no reference to alignFrame retained by menu item listener
          */
-        if (menuItem.getActionListeners().length > 0) {
+        if (menuItem.getActionListeners().length > 0)
+        {
           menuItem.removeActionListener(menuItem.getActionListeners()[0]);
         }
-        windowMenu.remove(menuItem);
+        getInstance().windowMenu.remove(menuItem);
       }
     });
 
-    menuItem.addActionListener(new ActionListener() {
+    menuItem.addActionListener(new ActionListener()
+    {
       @Override
-      public void actionPerformed(ActionEvent e) {
-        try {
+      public void actionPerformed(ActionEvent e)
+      {
+        try
+        {
           frame.setSelected(true);
           frame.setIcon(false);
-        } catch (java.beans.PropertyVetoException ex) {
-
+        } catch (java.beans.PropertyVetoException ex)
+        {
+          // System.err.println(ex.toString());
         }
       }
     });
 
     setKeyBindings(frame);
 
-    desktop.add(frame);
+    getDesktopPane().add(frame);
 
-    windowMenu.add(menuItem);
+    getInstance().windowMenu.add(menuItem);
 
     frame.toFront();
-    try {
+    try
+    {
       frame.setSelected(true);
       frame.requestFocus();
-    } catch (java.beans.PropertyVetoException ve) {
-    } catch (java.lang.ClassCastException cex) {
+    } catch (java.beans.PropertyVetoException ve)
+    {
+    } catch (java.lang.ClassCastException cex)
+    {
       Cache.log.warn(
-          "Squashed a possible GUI implementation error. If you can recreate this, please look at https://issues.jalview.org/browse/JAL-869",
-          cex);
+              "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
+              cex);
     }
   }
 
   /**
-   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
-   * window
+   * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
+   * the window
    * 
    * @param frame
    */
-  private static void setKeyBindings(JInternalFrame frame) {
-    @SuppressWarnings("serial")
-    final Action closeAction = new AbstractAction() {
+  private static void setKeyBindings(JInternalFrame frame)
+  {
+    final Action closeAction = new AbstractAction()
+    {
       @Override
-      public void actionPerformed(ActionEvent e) {
+      public void actionPerformed(ActionEvent e)
+      {
         frame.dispose();
       }
     };
@@ -879,7 +1039,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK);
     KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W, ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
 
-    InputMap inputMap = frame.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+    InputMap inputMap = frame
+            .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
     String ctrlW = ctrlWKey.toString();
     inputMap.put(ctrlWKey, ctrlW);
     inputMap.put(cmdWKey, ctrlW);
@@ -889,37 +1050,45 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void lostOwnership(Clipboard clipboard, Transferable contents) {
-    if (!internalCopy) {
-      Desktop.jalviewClipboard = null;
+  public void lostOwnership(Clipboard clipboard, Transferable contents)
+  {
+    if (!internalCopy)
+    {
+      jalviewClipboard = null;
     }
 
     internalCopy = false;
   }
 
   @Override
-  public void dragEnter(DropTargetDragEvent evt) {
+  public void dragEnter(DropTargetDragEvent evt)
+  {
   }
 
   @Override
-  public void dragExit(DropTargetEvent evt) {
+  public void dragExit(DropTargetEvent evt)
+  {
   }
 
   @Override
-  public void dragOver(DropTargetDragEvent evt) {
+  public void dragOver(DropTargetDragEvent evt)
+  {
   }
 
   @Override
-  public void dropActionChanged(DropTargetDragEvent evt) {
+  public void dropActionChanged(DropTargetDragEvent evt)
+  {
   }
 
   /**
    * DOCUMENT ME!
    * 
-   * @param evt DOCUMENT ME!
+   * @param evt
+   *          DOCUMENT ME!
    */
   @Override
-  public void drop(DropTargetDropEvent evt) {
+  public void drop(DropTargetDropEvent evt)
+  {
     boolean success = true;
     // JAL-1552 - acceptDrop required before getTransferable call for
     // Java's Transferable for native dnd
@@ -928,35 +1097,47 @@ public class Desktop extends jalview.jbgui.GDesktop
     List<Object> files = new ArrayList<>();
     List<DataSourceType> protocols = new ArrayList<>();
 
-    try {
-      Desktop.transferFromDropTarget(files, protocols, evt, t);
-    } catch (Exception e) {
+    try
+    {
+      transferFromDropTarget(files, protocols, evt, t);
+    } catch (Exception e)
+    {
       e.printStackTrace();
       success = false;
     }
 
-    if (files != null) {
-      try {
-        for (int i = 0; i < files.size(); i++) {
+    if (files != null)
+    {
+      try
+      {
+        for (int i = 0; i < files.size(); i++)
+        {
           // BH 2018 File or String
           Object file = files.get(i);
           String fileName = file.toString();
-          DataSourceType protocol = (protocols == null) ? DataSourceType.FILE : protocols.get(i);
+          DataSourceType protocol = (protocols == null)
+                  ? DataSourceType.FILE
+                  : protocols.get(i);
           FileFormatI format = null;
 
-          if (fileName.endsWith(".jar")) {
+          if (fileName.endsWith(".jar"))
+          {
             format = FileFormat.Jalview;
 
-          } else {
+          }
+          else
+          {
             format = new IdentifyFile().identify(file, protocol);
           }
-          if (file instanceof File) {
+          if (file instanceof File)
+          {
             Platform.cacheFileData((File) file);
           }
           new FileLoader().LoadFile(null, file, protocol, format);
 
         }
-      } catch (Exception ex) {
+      } catch (Exception ex)
+      {
         success = false;
       }
     }
@@ -967,21 +1148,27 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e DOCUMENT ME!
+   * @param e
+   *          DOCUMENT ME!
    */
   @Override
-  public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport) {
+  public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
+  {
     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-    JalviewFileChooser chooser = JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat,
-        BackupFiles.getEnabled());
+    JalviewFileChooser chooser = JalviewFileChooser.forRead(
+            Cache.getProperty("LAST_DIRECTORY"), fileFormat,
+            BackupFiles.getEnabled());
 
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(MessageManager.getString("label.open_local_file"));
+    chooser.setDialogTitle(
+            MessageManager.getString("label.open_local_file"));
     chooser.setToolTipText(MessageManager.getString("action.open"));
 
-    chooser.setResponseHandler(0, new Runnable() {
+    chooser.setResponseHandler(0, new Runnable()
+    {
       @Override
-      public void run() {
+      public void run()
+      {
         File selectedFile = chooser.getSelectedFile();
         Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
 
@@ -989,18 +1176,23 @@ public class Desktop extends jalview.jbgui.GDesktop
 
         /*
          * Call IdentifyFile to verify the file contains what its extension implies.
-         * Skip this step for dynamically added file formats, because IdentifyFile does
-         * not know how to recognise them.
+         * Skip this step for dynamically added file formats, because
+         * IdentifyFile does not know how to recognise them.
          */
-        if (FileFormats.getInstance().isIdentifiable(format)) {
-          try {
-            format = new IdentifyFile().identify(selectedFile, DataSourceType.FILE);
-          } catch (FileFormatException e) {
+        if (FileFormats.getInstance().isIdentifiable(format))
+        {
+          try
+          {
+            format = new IdentifyFile().identify(selectedFile,
+                    DataSourceType.FILE);
+          } catch (FileFormatException e)
+          {
             // format = null; //??
           }
         }
 
-        new FileLoader().LoadFile(viewport, selectedFile, DataSourceType.FILE, format);
+        new FileLoader().LoadFile(viewport, selectedFile,
+                DataSourceType.FILE, format);
       }
     });
     chooser.showOpenDialog(this);
@@ -1012,23 +1204,28 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @param viewport
    */
   @Override
-  public void inputURLMenuItem_actionPerformed(AlignViewport viewport) {
+  public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
+  {
     // This construct allows us to have a wider textfield
     // for viewing
-    JLabel label = new JLabel(MessageManager.getString("label.input_file_url"));
+    JLabel label = new JLabel(
+            MessageManager.getString("label.input_file_url"));
 
     JPanel panel = new JPanel(new GridLayout(2, 1));
     panel.add(label);
 
     /*
-     * the URL to fetch is input in Java: an editable combobox with history JS:
-     * (pending JAL-3038) a plain text field
+     * the URL to fetch is
+     * Java: an editable combobox with history
+     * JS: (pending JAL-3038) a plain text field
      */
     JComponent history;
-    String urlBase = "https://www.";
-    if (Platform.isJS()) {
+    String urlBase = "http://www.";
+    if (Platform.isJS())
+    {
       history = new JTextField(urlBase, 35);
-    } else
+    }
+    else
     /**
      * Java only
      * 
@@ -1040,8 +1237,10 @@ public class Desktop extends jalview.jbgui.GDesktop
       asCombo.setEditable(true);
       asCombo.addItem(urlBase);
       String historyItems = Cache.getProperty("RECENT_URL");
-      if (historyItems != null) {
-        for (String token : historyItems.split("\\t")) {
+      if (historyItems != null)
+      {
+        for (String token : historyItems.split("\\t"))
+        {
           asCombo.addItem(token);
         }
       }
@@ -1051,9 +1250,11 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     Object[] options = new Object[] { MessageManager.getString("action.ok"),
         MessageManager.getString("action.cancel") };
-    Runnable action = new Runnable() {
+    Runnable action = new Runnable()
+    {
       @Override
-      public void run() {
+      public void run()
+      {
         @SuppressWarnings("unchecked")
         String url = (history instanceof JTextField ? ((JTextField) history).getText()
             : ((JComboBox<String>) history).getEditor().getItem().toString().trim());
@@ -1066,72 +1267,96 @@ public class Desktop extends jalview.jbgui.GDesktop
           }
         } else {
           FileFormatI format = null;
-          try {
+          try
+          {
             format = new IdentifyFile().identify(url, DataSourceType.URL);
-          } catch (FileFormatException e) {
+          } catch (FileFormatException e)
+          {
             // TODO revise error handling, distinguish between
             // URL not found and response not valid
           }
 
-          if (format == null) {
-            String msg = MessageManager.formatMessage("label.couldnt_locate", url);
-            JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
-                MessageManager.getString("label.url_not_found"), JvOptionPane.WARNING_MESSAGE);
+          if (format == null)
+          {
+            String msg = MessageManager
+                    .formatMessage("label.couldnt_locate", url);
+            JvOptionPane.showInternalMessageDialog(getDesktopPane(), msg,
+                    MessageManager.getString("label.url_not_found"),
+                    JvOptionPane.WARNING_MESSAGE);
 
             return;
           }
 
-          if (viewport != null) {
-            new FileLoader().LoadFile(viewport, url, DataSourceType.URL, format);
-          } else {
+          if (viewport != null)
+          {
+            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
+                    format);
+          }
+          else
+          {
             new FileLoader().LoadFile(url, DataSourceType.URL, format);
           }
         }
       }
     };
-    String dialogOption = MessageManager.getString("label.input_alignment_from_url");
-    JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action).showInternalDialog(panel, dialogOption,
-        JvOptionPane.YES_NO_CANCEL_OPTION, JvOptionPane.PLAIN_MESSAGE, null, options,
-        MessageManager.getString("action.ok"));
+    String dialogOption = MessageManager
+            .getString("label.input_alignment_from_url");
+    JvOptionPane.newOptionDialog(desktopPane).setResponseHandler(0, action)
+            .showInternalDialog(panel, dialogOption,
+                    JvOptionPane.YES_NO_CANCEL_OPTION,
+                    JvOptionPane.PLAIN_MESSAGE, null, options,
+                    MessageManager.getString("action.ok"));
   }
 
   /**
    * Opens the CutAndPaste window for the user to paste an alignment in to
    * 
-   * @param viewPanel - if not null, the pasted alignment is added to the current
-   *                  alignment; if null, to a new alignment window
+   * @param viewPanel
+   *          - if not null, the pasted alignment is added to the current
+   *          alignment; if null, to a new alignment window
    */
   @Override
-  public void inputTextboxMenuItem_actionPerformed(AlignmentViewPanel viewPanel) {
+  public void inputTextboxMenuItem_actionPerformed(
+          AlignmentViewPanel viewPanel)
+  {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
     cap.setForInput(viewPanel);
-    Desktop.addInternalFrame(cap, MessageManager.getString("label.cut_paste_alignmen_file"), true, 600, 500);
+    addInternalFrame(cap,
+            MessageManager.getString("label.cut_paste_alignmen_file"),
+            FRAME_MAKE_VISIBLE, 600, 500, FRAME_ALLOW_RESIZE,
+            FRAME_SET_MIN_SIZE_300);
   }
 
   /*
    * Exit the program
    */
   @Override
-  public void quit() {
+  public void quit()
+  {
     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()));
+    storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
+            getWidth(), getHeight()));
 
-    if (jconsole != null) {
+    if (jconsole != null)
+    {
       storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
       jconsole.stopConsole();
     }
-    if (jvnews != null) {
+    if (jvnews != null)
+    {
       storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
 
     }
-    if (dialogExecutor != null) {
+    if (dialogExecutor != null)
+    {
       dialogExecutor.shutdownNow();
     }
     closeAll_actionPerformed(null);
 
-    if (groovyConsole != null) {
+    if (groovyConsole != null)
+    {
       // suppress a possible repeat prompt to save script
       groovyConsole.setDirty(false);
       groovyConsole.exit();
@@ -1139,9 +1364,11 @@ public class Desktop extends jalview.jbgui.GDesktop
     System.exit(0);
   }
 
-  private void storeLastKnownDimensions(String string, Rectangle jc) {
-    Cache.log.debug("Storing last known dimensions for " + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
-        + " height:" + jc.height);
+  private void storeLastKnownDimensions(String string, Rectangle jc)
+  {
+    Cache.log.debug("Storing last known dimensions for " + string + ": x:"
+            + jc.x + " y:" + jc.y + " width:" + jc.width + " height:"
+            + jc.height);
 
     Cache.setProperty(string + "SCREEN_X", jc.x + "");
     Cache.setProperty(string + "SCREEN_Y", jc.y + "");
@@ -1152,13 +1379,17 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e DOCUMENT ME!
+   * @param e
+   *          DOCUMENT ME!
    */
   @Override
-  public void aboutMenuItem_actionPerformed(ActionEvent e) {
-    new Thread(new Runnable() {
+  public void aboutMenuItem_actionPerformed(ActionEvent e)
+  {
+    new Thread(new Runnable()
+    {
       @Override
-      public void run() {
+      public void run()
+      {
         new SplashScreen(false);
       }
     }).start();
@@ -1166,12 +1397,13 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Returns the html text for the About screen, including any available version
-   * number, build details, author details and citation reference, but without the
-   * enclosing {@code html} tags
+   * number, build details, author details and citation reference, but without
+   * the enclosing {@code html} tags
    * 
    * @return
    */
-  public String getAboutMessage() {
+  public String getAboutMessage()
+  {
     StringBuilder message = new StringBuilder(1024);
     message.append("<div style=\"font-family: sans-serif;\">").append("<h1><strong>Version: ")
         .append(Cache.getProperty("VERSION")).append("</strong></h1>").append("<strong>Built: <em>")
@@ -1203,7 +1435,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     message.append(CITATION);
 
     message.append("</div>");
-
     return message.toString();
   }
 
@@ -1230,13 +1461,17 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void closeAll_actionPerformed(ActionEvent e) {
+  public void closeAll_actionPerformed(ActionEvent e)
+  {
     // TODO show a progress bar while closing?
-    JInternalFrame[] frames = desktop.getAllFrames();
-    for (int i = 0; i < frames.length; i++) {
-      try {
+    JInternalFrame[] frames = desktopPane.getAllFrames();
+    for (int i = 0; i < frames.length; i++)
+    {
+      try
+      {
         frames[i].setClosed(true);
-      } catch (java.beans.PropertyVetoException ex) {
+      } catch (java.beans.PropertyVetoException ex)
+      {
       }
     }
     Jalview.setCurrentAlignFrame(null);
@@ -1246,23 +1481,28 @@ public class Desktop extends jalview.jbgui.GDesktop
      * reset state of singleton objects as appropriate (clear down session state
      * when all windows are closed)
      */
-    StructureSelectionManager ssm = StructureSelectionManager.getStructureSelectionManager(this);
-    if (ssm != null) {
+    StructureSelectionManager ssm = StructureSelectionManager
+            .getStructureSelectionManager(this);
+    if (ssm != null)
+    {
       ssm.resetAll();
     }
   }
 
   @Override
-  public void raiseRelated_actionPerformed(ActionEvent e) {
+  public void raiseRelated_actionPerformed(ActionEvent e)
+  {
     reorderAssociatedWindows(false, false);
   }
 
   @Override
-  public void minimizeAssociated_actionPerformed(ActionEvent e) {
+  public void minimizeAssociated_actionPerformed(ActionEvent e)
+  {
     reorderAssociatedWindows(true, false);
   }
 
-  void closeAssociatedWindows() {
+  void closeAssociatedWindows()
+  {
     reorderAssociatedWindows(false, true);
   }
 
@@ -1273,7 +1513,8 @@ public class Desktop extends jalview.jbgui.GDesktop
    * ActionEvent)
    */
   @Override
-  protected void garbageCollect_actionPerformed(ActionEvent e) {
+  protected void garbageCollect_actionPerformed(ActionEvent e)
+  {
     // We simply collect the garbage
     Cache.log.debug("Collecting garbage...");
     System.gc();
@@ -1283,12 +1524,14 @@ public class Desktop extends jalview.jbgui.GDesktop
   /*
    * (non-Javadoc)
    * 
-   * @see jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.
-   * ActionEvent )
+   * @see
+   * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
+   * )
    */
   @Override
-  protected void showMemusage_actionPerformed(ActionEvent e) {
-    desktop.showMemoryUsage(showMemusage.isSelected());
+  protected void showMemusage_actionPerformed(ActionEvent e)
+  {
+    desktopPane.showMemoryUsage(showMemusage.isSelected());
   }
 
   /*
@@ -1299,7 +1542,8 @@ public class Desktop extends jalview.jbgui.GDesktop
    * )
    */
   @Override
-  protected void showConsole_actionPerformed(ActionEvent e) {
+  protected void showConsole_actionPerformed(ActionEvent e)
+  {
     showConsole(showConsole.isSelected());
   }
 
@@ -1310,61 +1554,90 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param selected
    */
-  void showConsole(boolean selected) {
+  void showConsole(boolean selected)
+  {
     // TODO: decide if we should update properties file
     if (jconsole != null) // BH 2018
     {
       showConsole.setSelected(selected);
-      Cache.setProperty("SHOW_JAVA_CONSOLE", Boolean.valueOf(selected).toString());
+      Cache.setProperty("SHOW_JAVA_CONSOLE",
+              Boolean.valueOf(selected).toString());
       jconsole.setVisible(selected);
     }
   }
 
-  void reorderAssociatedWindows(boolean minimize, boolean close) {
-    JInternalFrame[] frames = desktop.getAllFrames();
-    if (frames == null || frames.length < 1) {
+  void reorderAssociatedWindows(boolean minimize, boolean close)
+  {
+    JInternalFrame[] frames = desktopPane.getAllFrames();
+    if (frames == null || frames.length < 1)
+    {
       return;
     }
 
-    AlignmentViewport source = null, target = null;
-    if (frames[0] instanceof AlignFrame) {
+    AlignViewportI source = null;
+    AlignViewportI target = null;
+    if (frames[0] instanceof AlignFrame)
+    {
       source = ((AlignFrame) frames[0]).getCurrentView();
-    } else if (frames[0] instanceof TreePanel) {
+    }
+    else if (frames[0] instanceof TreePanel)
+    {
       source = ((TreePanel) frames[0]).getViewPort();
-    } else if (frames[0] instanceof PCAPanel) {
+    }
+    else if (frames[0] instanceof PCAPanel)
+    {
       source = ((PCAPanel) frames[0]).av;
-    } else if (frames[0].getContentPane() instanceof PairwiseAlignPanel) {
+    }
+    else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
+    {
       source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
     }
 
-    if (source != null) {
-      for (int i = 0; i < frames.length; i++) {
+    if (source != null)
+    {
+      for (int i = 0; i < frames.length; i++)
+      {
         target = null;
-        if (frames[i] == null) {
+        if (frames[i] == null)
+        {
           continue;
         }
-        if (frames[i] instanceof AlignFrame) {
+        if (frames[i] instanceof AlignFrame)
+        {
           target = ((AlignFrame) frames[i]).getCurrentView();
-        } else if (frames[i] instanceof TreePanel) {
+        }
+        else if (frames[i] instanceof TreePanel)
+        {
           target = ((TreePanel) frames[i]).getViewPort();
-        } else if (frames[i] instanceof PCAPanel) {
+        }
+        else if (frames[i] instanceof PCAPanel)
+        {
           target = ((PCAPanel) frames[i]).av;
-        } else if (frames[i].getContentPane() instanceof PairwiseAlignPanel) {
+        }
+        else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
+        {
           target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
         }
 
-        if (source == target) {
-          try {
-            if (close) {
+        if (source == target)
+        {
+          try
+          {
+            if (close)
+            {
               frames[i].setClosed(true);
-            } else {
+            }
+            else
+            {
               frames[i].setIcon(minimize);
-              if (!minimize) {
+              if (!minimize)
+              {
                 frames[i].toFront();
               }
             }
 
-          } catch (java.beans.PropertyVetoException ex) {
+          } catch (java.beans.PropertyVetoException ex)
+          {
           }
         }
       }
@@ -1374,7 +1647,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * DOCUMENT ME!
    * 
-   * @param e DOCUMENT ME!
+   * @param e
+   *          DOCUMENT ME!
    */
   @Override
   protected void preferences_actionPerformed(ActionEvent e) {
@@ -1386,66 +1660,84 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Jalview project file
    */
   @Override
-  public void saveState_actionPerformed() {
+  public void saveState_actionPerformed()
+  {
     saveState_actionPerformed(false);
   }
 
-  public void saveState_actionPerformed(boolean saveAs) {
+  public void saveState_actionPerformed(boolean saveAs)
+  {
     java.io.File projectFile = getProjectFile();
     // autoSave indicates we already have a file and don't need to ask
-    boolean autoSave = projectFile != null && !saveAs && BackupFiles.getEnabled();
+    boolean autoSave = projectFile != null && !saveAs
+            && BackupFiles.getEnabled();
 
     // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
     // saveAs="+saveAs+", Backups
     // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
 
     boolean approveSave = false;
-    if (!autoSave) {
-      JalviewFileChooser chooser = new JalviewFileChooser("jvp", "Jalview Project");
+    if (!autoSave)
+    {
+      JalviewFileChooser chooser = new JalviewFileChooser("jvp",
+              "Jalview Project");
 
       chooser.setFileView(new JalviewFileView());
       chooser.setDialogTitle(MessageManager.getString("label.save_state"));
 
       int value = chooser.showSaveDialog(this);
 
-      if (value == JalviewFileChooser.APPROVE_OPTION) {
+      if (value == JalviewFileChooser.APPROVE_OPTION)
+      {
         projectFile = chooser.getSelectedFile();
         setProjectFile(projectFile);
         approveSave = true;
       }
     }
-
     if (approveSave || autoSave) {
       final Desktop me = this;
       final java.io.File chosenFile = projectFile;
-      new Thread(new Runnable() {
+      new Thread(new Runnable()
+      {
         @Override
-        public void run() {
+        public void run()
+        {
           // TODO: refactor to Jalview desktop session controller action.
-          setProgressBar(
-              MessageManager.formatMessage("label.saving_jalview_project", new Object[] { chosenFile.getName() }),
-              chosenFile.hashCode());
+          setProgressBar(MessageManager.formatMessage(
+                  "label.saving_jalview_project", new Object[]
+                  { chosenFile.getName() }), chosenFile.hashCode());
           Cache.setProperty("LAST_DIRECTORY", chosenFile.getParent());
           // TODO catch and handle errors for savestate
           // TODO prevent user from messing with the Desktop whilst we're saving
-          try {
+          try
+          {
             boolean doBackup = BackupFiles.getEnabled();
-            BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
+            BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile)
+                    : null;
 
-            new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
+            new Jalview2XML().saveState(
+                    doBackup ? backupfiles.getTempFile() : chosenFile);
 
-            if (doBackup) {
+            if (doBackup)
+            {
               backupfiles.setWriteSuccess(true);
               backupfiles.rollBackupsAndRenameTempFile();
             }
-          } catch (OutOfMemoryError oom) {
-            new OOMWarning("Whilst saving current state to " + chosenFile.getName(), oom);
-          } catch (Exception ex) {
-            Cache.log.error("Problems whilst trying to save to " + chosenFile.getName(), ex);
+          } catch (OutOfMemoryError oom)
+          {
+            new OOMWarning("Whilst saving current state to "
+                    + chosenFile.getName(), oom);
+          } catch (Exception ex)
+          {
+            Cache.log.error("Problems whilst trying to save to "
+                    + chosenFile.getName(), ex);
             JvOptionPane.showMessageDialog(me,
-                MessageManager.formatMessage("label.error_whilst_saving_current_state_to",
-                    new Object[] { chosenFile.getName() }),
-                MessageManager.getString("label.couldnt_save_project"), JvOptionPane.WARNING_MESSAGE);
+                    MessageManager.formatMessage(
+                            "label.error_whilst_saving_current_state_to",
+                            new Object[]
+                            { chosenFile.getName() }),
+                    MessageManager.getString("label.couldnt_save_project"),
+                    JvOptionPane.WARNING_MESSAGE);
           }
           setProgressBar(null, chosenFile.hashCode());
         }
@@ -1454,15 +1746,18 @@ public class Desktop extends jalview.jbgui.GDesktop
   }
 
   @Override
-  public void saveAsState_actionPerformed(ActionEvent e) {
+  public void saveAsState_actionPerformed(ActionEvent e)
+  {
     saveState_actionPerformed(true);
   }
 
-  private void setProjectFile(File choice) {
+  private void setProjectFile(File choice)
+  {
     this.projectFile = choice;
   }
 
-  public File getProjectFile() {
+  public File getProjectFile()
+  {
     return this.projectFile;
   }
 
@@ -1471,46 +1766,62 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Jalview project
    */
   @Override
-  public void loadState_actionPerformed() {
+  public void loadState_actionPerformed()
+  {
     final String[] suffix = new String[] { "jvp", "jar" };
-    final String[] desc = new String[] { "Jalview Project", "Jalview Project (old)" };
-    JalviewFileChooser chooser = new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
-        "Jalview Project", true, BackupFiles.getEnabled()); // last two
-                                                            // booleans:
-                                                            // allFiles,
+    final String[] desc = new String[] { "Jalview Project",
+        "Jalview Project (old)" };
+    JalviewFileChooser chooser = new JalviewFileChooser(
+            Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
+            "Jalview Project", true, BackupFiles.getEnabled()); // last two
+                                                                // booleans:
+                                                                // allFiles,
     // allowBackupFiles
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
-    chooser.setResponseHandler(0, new Runnable() {
+    chooser.setResponseHandler(0, new Runnable()
+    {
       @Override
-      public void run() {
+      public void run()
+      {
         File selectedFile = chooser.getSelectedFile();
         setProjectFile(selectedFile);
         String choice = selectedFile.getAbsolutePath();
         Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
-        new Thread(new Runnable() {
+        new Thread(new Runnable()
+        {
           @Override
-          public void run() {
-            try {
+          public void run()
+          {
+            try
+            {
               new Jalview2XML().loadJalviewAlign(selectedFile);
-            } catch (OutOfMemoryError oom) {
+            } catch (OutOfMemoryError oom)
+            {
               new OOMWarning("Whilst loading project from " + choice, oom);
-            } catch (Exception ex) {
-              Cache.log.error("Problems whilst loading project from " + choice, ex);
-              JvOptionPane.showMessageDialog(Desktop.desktop,
-                  MessageManager.formatMessage("label.error_whilst_loading_project_from", new Object[] { choice }),
-                  MessageManager.getString("label.couldnt_load_project"), JvOptionPane.WARNING_MESSAGE);
+            } catch (Exception ex)
+            {
+              Cache.log.error(
+                      "Problems whilst loading project from " + choice, ex);
+              JvOptionPane.showMessageDialog(getDesktopPane(),
+                      MessageManager.formatMessage(
+                              "label.error_whilst_loading_project_from",
+                              new Object[]
+                              { choice }),
+                      MessageManager
+                              .getString("label.couldnt_load_project"),
+                      JvOptionPane.WARNING_MESSAGE);
             }
           }
         }, "Project Loader").start();
       }
     });
-
     chooser.showOpenDialog(this);
   }
 
   @Override
-  public void inputSequence_actionPerformed(ActionEvent e) {
+  public void inputSequence_actionPerformed(ActionEvent e)
+  {
     new SequenceFetcher(this);
   }
 
@@ -1518,19 +1829,24 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
 
-  public void startLoading(final Object fileName) {
-    if (fileLoadingCount == 0) {
-      fileLoadingPanels
-          .add(addProgressPanel(MessageManager.formatMessage("label.loading_file", new Object[] { fileName })));
+  public void startLoading(final Object fileName)
+  {
+    if (fileLoadingCount == 0)
+    {
+      fileLoadingPanels.add(addProgressPanel(MessageManager
+              .formatMessage("label.loading_file", new Object[]
+              { fileName })));
     }
     fileLoadingCount++;
   }
 
-  private JPanel addProgressPanel(String string) {
-    if (progressPanel == null) {
+  private JPanel addProgressPanel(String string)
+  {
+    if (progressPanel == null)
+    {
       progressPanel = new JPanel(new GridLayout(1, 1));
       totalProgressCount = 0;
-      instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
+      getContentPane().add(progressPanel, BorderLayout.SOUTH);
     }
     JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
     JProgressBar progressBar = new JProgressBar();
@@ -1540,21 +1856,26 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     thisprogress.add(progressBar, BorderLayout.CENTER);
     progressPanel.add(thisprogress);
-    ((GridLayout) progressPanel.getLayout()).setRows(((GridLayout) progressPanel.getLayout()).getRows() + 1);
+    ((GridLayout) progressPanel.getLayout()).setRows(
+            ((GridLayout) progressPanel.getLayout()).getRows() + 1);
     ++totalProgressCount;
-    instance.validate();
+    validate();
     return thisprogress;
   }
 
   int totalProgressCount = 0;
 
-  private void removeProgressPanel(JPanel progbar) {
-    if (progressPanel != null) {
-      synchronized (progressPanel) {
+  private void removeProgressPanel(JPanel progbar)
+  {
+    if (progressPanel != null)
+    {
+      synchronized (progressPanel)
+      {
         progressPanel.remove(progbar);
         GridLayout gl = (GridLayout) progressPanel.getLayout();
         gl.setRows(gl.getRows() - 1);
-        if (--totalProgressCount < 1) {
+        if (--totalProgressCount < 1)
+        {
           this.getContentPane().remove(progressPanel);
           progressPanel = null;
         }
@@ -1563,10 +1884,13 @@ public class Desktop extends jalview.jbgui.GDesktop
     validate();
   }
 
-  public void stopLoading() {
+  public void stopLoading()
+  {
     fileLoadingCount--;
-    if (fileLoadingCount < 1) {
-      while (fileLoadingPanels.size() > 0) {
+    if (fileLoadingCount < 1)
+    {
+      while (fileLoadingPanels.size() > 0)
+      {
         removeProgressPanel(fileLoadingPanels.remove(0));
       }
       fileLoadingPanels.clear();
@@ -1575,35 +1899,45 @@ public class Desktop extends jalview.jbgui.GDesktop
     validate();
   }
 
-  public static int getViewCount(String alignmentId) {
+  public static int getViewCount(String alignmentId)
+  {
     AlignmentViewport[] aps = getViewports(alignmentId);
     return (aps == null) ? 0 : aps.length;
   }
 
   /**
    * 
-   * @param alignmentId - if null, all sets are returned
+   * @param alignmentId
+   *          - if null, all sets are returned
    * @return all AlignmentPanels concerning the alignmentId sequence set
    */
-  public static AlignmentPanel[] getAlignmentPanels(String alignmentId) {
-    if (Desktop.desktop == null) {
+  public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
+  {
+    if (getDesktopPane() == null)
+    {
       // no frames created and in headless mode
       // TODO: verify that frames are recoverable when in headless mode
       return null;
     }
     List<AlignmentPanel> aps = new ArrayList<>();
     AlignFrame[] frames = getAlignFrames();
-    if (frames == null) {
+    if (frames == null)
+    {
       return null;
     }
-    for (AlignFrame af : frames) {
-      for (AlignmentPanel ap : af.alignPanels) {
-        if (alignmentId == null || alignmentId.equals(ap.av.getSequenceSetId())) {
+    for (AlignFrame af : frames)
+    {
+      for (AlignmentPanel ap : af.alignPanels)
+      {
+        if (alignmentId == null
+                || alignmentId.equals(ap.av.getSequenceSetId()))
+        {
           aps.add(ap);
         }
       }
     }
-    if (aps.size() == 0) {
+    if (aps.size() == 0)
+    {
       return null;
     }
     AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
@@ -1613,29 +1947,42 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * get all the viewports on an alignment.
    * 
-   * @param sequenceSetId unique alignment id (may be null - all viewports
-   *                      returned in that case)
+   * @param sequenceSetId
+   *          unique alignment id (may be null - all viewports returned in that
+   *          case)
    * @return all viewports on the alignment bound to sequenceSetId
    */
-  public static AlignmentViewport[] getViewports(String sequenceSetId) {
+  public static AlignmentViewport[] getViewports(String sequenceSetId)
+  {
     List<AlignmentViewport> viewp = new ArrayList<>();
-    if (desktop != null) {
-      AlignFrame[] frames = Desktop.getAlignFrames();
-
-      for (AlignFrame afr : frames) {
-        if (sequenceSetId == null || afr.getViewport().getSequenceSetId().equals(sequenceSetId)) {
-          if (afr.alignPanels != null) {
-            for (AlignmentPanel ap : afr.alignPanels) {
-              if (sequenceSetId == null || sequenceSetId.equals(ap.av.getSequenceSetId())) {
+    if (getDesktopPane() != null)
+    {
+      AlignFrame[] frames = getAlignFrames();
+
+      for (AlignFrame afr : frames)
+      {
+        if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
+                .equals(sequenceSetId))
+        {
+          if (afr.alignPanels != null)
+          {
+            for (AlignmentPanel ap : afr.alignPanels)
+            {
+              if (sequenceSetId == null
+                      || sequenceSetId.equals(ap.av.getSequenceSetId()))
+              {
                 viewp.add(ap.av);
               }
             }
-          } else {
+          }
+          else
+          {
             viewp.add(afr.getViewport());
           }
         }
       }
-      if (viewp.size() > 0) {
+      if (viewp.size() > 0)
+      {
         return viewp.toArray(new AlignmentViewport[viewp.size()]);
       }
     }
@@ -1647,47 +1994,56 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param af
    */
-  public static void explodeViews(AlignFrame af) {
+  public static void explodeViews(AlignFrame af)
+  {
     int size = af.alignPanels.size();
-    if (size < 2) {
+    if (size < 2)
+    {
       return;
     }
 
     // FIXME: ideally should use UI interface API
-    FeatureSettings viewFeatureSettings = (af.featureSettings != null && af.featureSettings.isOpen())
-        ? af.featureSettings
-        : null;
+    FeatureSettings viewFeatureSettings = (af.featureSettings != null
+            && af.featureSettings.isOpen()) ? af.featureSettings : null;
     Rectangle fsBounds = af.getFeatureSettingsGeometry();
-    for (int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++)
+    {
       AlignmentPanel ap = af.alignPanels.get(i);
 
       AlignFrame newaf = new AlignFrame(ap);
 
       // transfer reference for existing feature settings to new alignFrame
-      if (ap == af.alignPanel) {
-        if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap) {
+      if (ap == af.alignPanel)
+      {
+        if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap)
+        {
           newaf.featureSettings = viewFeatureSettings;
         }
         newaf.setFeatureSettingsGeometry(fsBounds);
       }
 
       /*
-       * Restore the view's last exploded frame geometry if known. Multiple views from
-       * one exploded frame share and restore the same (frame) position and size.
+       * Restore the view's last exploded frame geometry if known. Multiple
+       * views from one exploded frame share and restore the same (frame)
+       * position and size.
        */
       Rectangle geometry = ap.av.getExplodedGeometry();
-      if (geometry != null) {
+      if (geometry != null)
+      {
         newaf.setBounds(geometry);
       }
 
       ap.av.setGatherViewsHere(false);
 
-      addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+      addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
+              AlignFrame.DEFAULT_HEIGHT);
       // and materialise a new feature settings dialog instance for the new
       // alignframe
       // (closes the old as if 'OK' was pressed)
-      if (ap == af.alignPanel && newaf.featureSettings != null && newaf.featureSettings.isOpen()
-          && af.alignPanel.getAlignViewport().isShowSequenceFeatures()) {
+      if (ap == af.alignPanel && newaf.featureSettings != null
+              && newaf.featureSettings.isOpen()
+              && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
+      {
         newaf.showFeatureSettingsUI();
       }
     }
@@ -1700,24 +2056,29 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Gather expanded views (separate AlignFrame's) with the same sequence set
-   * identifier back in to this frame as additional views, and close the expanded
-   * views. Note the expanded frames may themselves have multiple views. We take
-   * the lot.
+   * identifier back in to this frame as additional views, and close the
+   * expanded views. Note the expanded frames may themselves have multiple
+   * views. We take the lot.
    * 
    * @param source
    */
-  public void gatherViews(AlignFrame source) {
+  public void gatherViews(AlignFrame source)
+  {
     source.viewport.setGatherViewsHere(true);
     source.viewport.setExplodedGeometry(source.getBounds());
-    JInternalFrame[] frames = desktop.getAllFrames();
+    JInternalFrame[] frames = desktopPane.getAllFrames();
     String viewId = source.viewport.getSequenceSetId();
-    for (int t = 0; t < frames.length; t++) {
-      if (frames[t] instanceof AlignFrame && frames[t] != source) {
+    for (int t = 0; t < frames.length; t++)
+    {
+      if (frames[t] instanceof AlignFrame && frames[t] != source)
+      {
         AlignFrame af = (AlignFrame) frames[t];
         boolean gatherThis = false;
-        for (int a = 0; a < af.alignPanels.size(); a++) {
+        for (int a = 0; a < af.alignPanels.size(); a++)
+        {
           AlignmentPanel ap = af.alignPanels.get(a);
-          if (viewId.equals(ap.av.getSequenceSetId())) {
+          if (viewId.equals(ap.av.getSequenceSetId()))
+          {
             gatherThis = true;
             ap.av.setGatherViewsHere(false);
             ap.av.setExplodedGeometry(af.getBounds());
@@ -1725,13 +2086,19 @@ public class Desktop extends jalview.jbgui.GDesktop
           }
         }
 
-        if (gatherThis) {
-          if (af.featureSettings != null && af.featureSettings.isOpen()) {
-            if (source.featureSettings == null) {
+        if (gatherThis)
+        {
+          if (af.featureSettings != null && af.featureSettings.isOpen())
+          {
+            if (source.featureSettings == null)
+            {
               // preserve the feature settings geometry for this frame
               source.featureSettings = af.featureSettings;
-              source.setFeatureSettingsGeometry(af.getFeatureSettingsGeometry());
-            } else {
+              source.setFeatureSettingsGeometry(
+                      af.getFeatureSettingsGeometry());
+            }
+            else
+            {
               // close it and forget
               af.featureSettings.close();
             }
@@ -1743,14 +2110,15 @@ public class Desktop extends jalview.jbgui.GDesktop
     }
 
     // refresh the feature setting UI for the source frame if it exists
-    if (source.featureSettings != null && source.featureSettings.isOpen()) {
+    if (source.featureSettings != null && source.featureSettings.isOpen())
+    {
       source.showFeatureSettingsUI();
     }
-
   }
 
-  public JInternalFrame[] getAllFrames() {
-    return desktop.getAllFrames();
+  public JInternalFrame[] getAllFrames()
+  {
+    return desktopPane.getAllFrames();
   }
 
   /**
@@ -1759,37 +2127,49 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param url
    */
-  public void checkForQuestionnaire(String url) {
+  public void checkForQuestionnaire(String url)
+  {
     UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
     // javax.swing.SwingUtilities.invokeLater(jvq);
     new Thread(jvq).start();
   }
 
-  public void checkURLLinks() {
+  public void checkURLLinks()
+  {
     // Thread off the URL link checker
-    addDialogThread(new Runnable() {
+    addDialogThread(new Runnable()
+    {
       @Override
-      public void run() {
-        if (Cache.getDefault("CHECKURLLINKS", true)) {
+      public void run()
+      {
+        if (Cache.getDefault("CHECKURLLINKS", true))
+        {
           // check what the actual links are - if it's just the default don't
           // bother with the warning
-          List<String> links = Preferences.sequenceUrlLinks.getLinksForMenu();
+          List<String> links = Preferences.sequenceUrlLinks
+                  .getLinksForMenu();
 
           // only need to check links if there is one with a
           // SEQUENCE_ID which is not the default EMBL_EBI link
           ListIterator<String> li = links.listIterator();
           boolean check = false;
           List<JLabel> urls = new ArrayList<>();
-          while (li.hasNext()) {
+          while (li.hasNext())
+          {
             String link = li.next();
-            if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID) && !UrlConstants.isDefaultString(link)) {
+            if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
+                    && !UrlConstants.isDefaultString(link))
+            {
               check = true;
               int barPos = link.indexOf("|");
-              String urlMsg = barPos == -1 ? link : link.substring(0, barPos) + ": " + link.substring(barPos + 1);
+              String urlMsg = barPos == -1 ? link
+                      : link.substring(0, barPos) + ": "
+                              + link.substring(barPos + 1);
               urls.add(new JLabel(urlMsg));
             }
           }
-          if (!check) {
+          if (!check)
+          {
             return;
           }
 
@@ -1798,27 +2178,36 @@ public class Desktop extends jalview.jbgui.GDesktop
           JPanel msgPanel = new JPanel();
           msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
           msgPanel.add(Box.createVerticalGlue());
-          JLabel msg = new JLabel(MessageManager.getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
-          JLabel msg2 = new JLabel(MessageManager.getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
+          JLabel msg = new JLabel(MessageManager
+                  .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
+          JLabel msg2 = new JLabel(MessageManager
+                  .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
           msgPanel.add(msg);
-          for (JLabel url : urls) {
+          for (JLabel url : urls)
+          {
             msgPanel.add(url);
           }
           msgPanel.add(msg2);
 
-          final JCheckBox jcb = new JCheckBox(MessageManager.getString("label.do_not_display_again"));
-          jcb.addActionListener(new ActionListener() {
+          final JCheckBox jcb = new JCheckBox(
+                  MessageManager.getString("label.do_not_display_again"));
+          jcb.addActionListener(new ActionListener()
+          {
             @Override
-            public void actionPerformed(ActionEvent e) {
+            public void actionPerformed(ActionEvent e)
+            {
               // update Cache settings for "don't show this again"
               boolean showWarningAgain = !jcb.isSelected();
-              Cache.setProperty("CHECKURLLINKS", Boolean.valueOf(showWarningAgain).toString());
+              Cache.setProperty("CHECKURLLINKS",
+                      Boolean.valueOf(showWarningAgain).toString());
             }
           });
           msgPanel.add(jcb);
 
-          JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
-              MessageManager.getString("label.SEQUENCE_ID_no_longer_used"), JvOptionPane.WARNING_MESSAGE);
+          JvOptionPane.showMessageDialog(desktopPane, msgPanel,
+                  MessageManager
+                          .getString("label.SEQUENCE_ID_no_longer_used"),
+                  JvOptionPane.WARNING_MESSAGE);
         }
       }
     });
@@ -1826,11 +2215,13 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   /**
    * Proxy class for JDesktopPane which optionally displays the current memory
-   * usage and highlights the desktop area with a red bar if free memory runs low.
+   * usage and highlights the desktop area with a red bar if free memory runs
+   * low.
    * 
    * @author AMW
    */
-  public class MyDesktopPane extends JDesktopPane implements Runnable {
+  public class MyDesktopPane extends JDesktopPane implements Runnable
+  {
     private static final float ONE_MB = 1048576f;
 
     boolean showMemoryUsage = false;
@@ -1839,33 +2230,41 @@ public class Desktop extends jalview.jbgui.GDesktop
 
     java.text.NumberFormat df;
 
-    float maxMemory, allocatedMemory, freeMemory, totalFreeMemory, percentUsage;
+    float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
+            percentUsage;
 
-    public MyDesktopPane(boolean showMemoryUsage) {
+    public MyDesktopPane(boolean showMemoryUsage)
+    {
       showMemoryUsage(showMemoryUsage);
     }
 
-    public void showMemoryUsage(boolean showMemory) {
+    public void showMemoryUsage(boolean showMemory)
+    {
       this.showMemoryUsage = showMemory;
-      if (showMemory) {
+      if (showMemory)
+      {
         Thread worker = new Thread(this);
         worker.start();
       }
       repaint();
     }
 
-    public boolean isShowMemoryUsage() {
+    public boolean isShowMemoryUsage()
+    {
       return showMemoryUsage;
     }
 
     @Override
-    public void run() {
+    public void run()
+    {
       df = java.text.NumberFormat.getNumberInstance();
       df.setMaximumFractionDigits(2);
       runtime = Runtime.getRuntime();
 
-      while (showMemoryUsage) {
-        try {
+      while (showMemoryUsage)
+      {
+        try
+        {
           maxMemory = runtime.maxMemory() / ONE_MB;
           allocatedMemory = runtime.totalMemory() / ONE_MB;
           freeMemory = runtime.freeMemory() / ONE_MB;
@@ -1882,27 +2281,32 @@ public class Desktop extends jalview.jbgui.GDesktop
           repaint();
           // sleep after showing usage
           Thread.sleep(3000);
-        } catch (Exception ex) {
+        } catch (Exception ex)
+        {
           ex.printStackTrace();
         }
       }
     }
 
     @Override
-    public void paintComponent(Graphics g) {
-      if (showMemoryUsage && g != null && df != null) {
-        if (percentUsage < 20) {
+    public void paintComponent(Graphics g)
+    {
+      if (showMemoryUsage && g != null && df != null)
+      {
+        if (percentUsage < 20)
+        {
           g.setColor(Color.red);
         }
         FontMetrics fm = g.getFontMetrics();
-        if (fm != null) {
-          g.drawString(
-              MessageManager.formatMessage("label.memory_stats",
-                  new Object[] { df.format(totalFreeMemory), df.format(maxMemory), df.format(percentUsage) }),
-              10, getHeight() - fm.getHeight());
+        if (fm != null)
+        {
+          g.drawString(MessageManager.formatMessage("label.memory_stats",
+                  new Object[]
+                  { df.format(totalFreeMemory), df.format(maxMemory),
+                      df.format(percentUsage) }),
+                  10, getHeight() - fm.getHeight());
         }
       }
-
       // output debug scale message. Important for jalview.bin.HiDPISettingTest2
       Desktop.debugScaleMessage(Desktop.getDesktop().getGraphics());
     }
@@ -1913,36 +2317,45 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return an array of AlignFrame, or null if none found
    */
-  public static AlignFrame[] getAlignFrames() {
-    if (Jalview.isHeadlessMode()) {
-      // Desktop.desktop is null in headless mode
-      return new AlignFrame[] { Jalview.currentAlignFrame };
+  public static AlignFrame[] getAlignFrames()
+  {
+    if (Jalview.isHeadlessMode())
+    {
+      return new AlignFrame[] { Jalview.getInstance().currentAlignFrame };
     }
 
-    JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+    JInternalFrame[] frames = getDesktopPane().getAllFrames();
 
-    if (frames == null) {
+    if (frames == null)
+    {
       return null;
     }
     List<AlignFrame> avp = new ArrayList<>();
     // REVERSE ORDER
-    for (int i = frames.length - 1; i > -1; i--) {
-      if (frames[i] instanceof AlignFrame) {
+    for (int i = frames.length - 1; i > -1; i--)
+    {
+      if (frames[i] instanceof AlignFrame)
+      {
         avp.add((AlignFrame) frames[i]);
-      } else if (frames[i] instanceof SplitFrame) {
+      }
+      else if (frames[i] instanceof SplitFrame)
+      {
         /*
          * Also check for a split frame containing an AlignFrame
          */
         GSplitFrame sf = (GSplitFrame) frames[i];
-        if (sf.getTopFrame() instanceof AlignFrame) {
+        if (sf.getTopFrame() instanceof AlignFrame)
+        {
           avp.add((AlignFrame) sf.getTopFrame());
         }
-        if (sf.getBottomFrame() instanceof AlignFrame) {
+        if (sf.getBottomFrame() instanceof AlignFrame)
+        {
           avp.add((AlignFrame) sf.getBottomFrame());
         }
       }
     }
-    if (avp.size() == 0) {
+    if (avp.size() == 0)
+    {
       return null;
     }
     AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
@@ -1954,21 +2367,26 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return
    */
-  public GStructureViewer[] getJmols() {
-    JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+  public GStructureViewer[] getJmols()
+  {
+    JInternalFrame[] frames = desktopPane.getAllFrames();
 
-    if (frames == null) {
+    if (frames == null)
+    {
       return null;
     }
     List<GStructureViewer> avp = new ArrayList<>();
     // REVERSE ORDER
-    for (int i = frames.length - 1; i > -1; i--) {
-      if (frames[i] instanceof AppJmol) {
+    for (int i = frames.length - 1; i > -1; i--)
+    {
+      if (frames[i] instanceof AppJmol)
+      {
         GStructureViewer af = (GStructureViewer) frames[i];
         avp.add(af);
       }
     }
-    if (avp.size() == 0) {
+    if (avp.size() == 0)
+    {
       return null;
     }
     GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
@@ -1979,37 +2397,45 @@ public class Desktop extends jalview.jbgui.GDesktop
    * Add Groovy Support to Jalview
    */
   @Override
-  public void groovyShell_actionPerformed() {
-    try {
+  public void groovyShell_actionPerformed()
+  {
+    try
+    {
       openGroovyConsole();
-    } catch (Exception ex) {
+    } catch (Exception ex)
+    {
       Cache.log.error("Groovy Shell Creation failed.", ex);
-      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+      JvOptionPane.showInternalMessageDialog(desktopPane,
 
-          MessageManager.getString("label.couldnt_create_groovy_shell"),
-          MessageManager.getString("label.groovy_support_failed"), JvOptionPane.ERROR_MESSAGE);
+              MessageManager.getString("label.couldnt_create_groovy_shell"),
+              MessageManager.getString("label.groovy_support_failed"),
+              JvOptionPane.ERROR_MESSAGE);
     }
   }
 
   /**
    * Open the Groovy console
    */
-  void openGroovyConsole() {
-    if (groovyConsole == null) {
+  void openGroovyConsole()
+  {
+    if (groovyConsole == null)
+    {
       groovyConsole = new groovy.ui.Console();
       groovyConsole.setVariable("Jalview", this);
       groovyConsole.run();
 
       /*
        * We allow only one console at a time, so that AlignFrame menu option
-       * 'Calculate | Run Groovy script' is unambiguous. Disable 'Groovy Console', and
-       * enable 'Run script', when the console is opened, and the reverse when it is
-       * closed
+       * 'Calculate | Run Groovy script' is unambiguous.
+       * Disable 'Groovy Console', and enable 'Run script', when the console is 
+       * opened, and the reverse when it is closed
        */
       Window window = (Window) groovyConsole.getFrame();
-      window.addWindowListener(new WindowAdapter() {
+      window.addWindowListener(new WindowAdapter()
+      {
         @Override
-        public void windowClosed(WindowEvent e) {
+        public void windowClosed(WindowEvent e)
+        {
           /*
            * rebind CMD-Q from Groovy Console to Jalview Quit
            */
@@ -2025,23 +2451,28 @@ public class Desktop extends jalview.jbgui.GDesktop
     ((Window) groovyConsole.getFrame()).setVisible(true);
 
     /*
-     * if we got this far, enable 'Run Groovy' in AlignFrame menus and disable
-     * opening a second console
+     * if we got this far, enable 'Run Groovy' in AlignFrame menus
+     * and disable opening a second console
      */
     enableExecuteGroovy(true);
   }
 
   /**
-   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
-   * when opened
+   * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
+   * binding when opened
    */
-  protected void addQuitHandler() {
-    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-        KeyStroke.getKeyStroke(KeyEvent.VK_Q, jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
-        "Quit");
-    getRootPane().getActionMap().put("Quit", new AbstractAction() {
+  protected void addQuitHandler()
+  {
+
+    getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
+            .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
+                    Platform.SHORTCUT_KEY_MASK),
+                    "Quit");
+    getRootPane().getActionMap().put("Quit", new AbstractAction()
+    {
       @Override
-      public void actionPerformed(ActionEvent e) {
+      public void actionPerformed(ActionEvent e)
+      {
         quit();
       }
     });
@@ -2050,18 +2481,22 @@ public class Desktop extends jalview.jbgui.GDesktop
   /**
    * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
    * 
-   * @param enabled true if Groovy console is open
+   * @param enabled
+   *          true if Groovy console is open
    */
-  public void enableExecuteGroovy(boolean enabled) {
+  public void enableExecuteGroovy(boolean enabled)
+  {
     /*
-     * disable opening a second Groovy console (or re-enable when the console is
-     * closed)
+     * disable opening a second Groovy console
+     * (or re-enable when the console is closed)
      */
     groovyShell.setEnabled(!enabled);
 
     AlignFrame[] alignFrames = getAlignFrames();
-    if (alignFrames != null) {
-      for (AlignFrame af : alignFrames) {
+    if (alignFrames != null)
+    {
+      for (AlignFrame af : alignFrames)
+      {
         af.setGroovyEnabled(enabled);
       }
     }
@@ -2080,22 +2515,37 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
    */
   @Override
-  public void setProgressBar(String message, long id) {
-    if (progressBars == null) {
+  public void setProgressBar(String message, long id)
+  {
+    // Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
+
+    if (progressBars == null)
+    {
       progressBars = new Hashtable<>();
       progressBarHandlers = new Hashtable<>();
     }
 
-    if (progressBars.get(Long.valueOf(id)) != null) {
+    if (progressBars.get(Long.valueOf(id)) != null)
+    {
       JPanel panel = progressBars.remove(Long.valueOf(id));
-      if (progressBarHandlers.contains(Long.valueOf(id))) {
+      if (progressBarHandlers.contains(Long.valueOf(id)))
+      {
         progressBarHandlers.remove(Long.valueOf(id));
       }
       removeProgressPanel(panel);
-    } else {
+    }
+    else
+    {
       progressBars.put(Long.valueOf(id), addProgressPanel(message));
     }
   }
+  
+  @Override
+  public void removeProgressBar(long id)
+  {
+    //TODO
+    throw new UnsupportedOperationException("not implemented");
+  }
 
   /*
    * (non-Javadoc)
@@ -2104,22 +2554,33 @@ public class Desktop extends jalview.jbgui.GDesktop
    * jalview.gui.IProgressIndicatorHandler)
    */
   @Override
-  public void registerHandler(final long id, final IProgressIndicatorHandler handler) {
-    if (progressBarHandlers == null || !progressBars.containsKey(Long.valueOf(id))) {
-      throw new Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
+  public void registerHandler(final long id,
+          final IProgressIndicatorHandler handler)
+  {
+    if (progressBarHandlers == null
+            || !progressBars.containsKey(Long.valueOf(id)))
+    {
+      throw new Error(MessageManager.getString(
+              "error.call_setprogressbar_before_registering_handler"));
     }
     progressBarHandlers.put(Long.valueOf(id), handler);
     final JPanel progressPanel = progressBars.get(Long.valueOf(id));
-    if (handler.canCancel()) {
-      JButton cancel = new JButton(MessageManager.getString("action.cancel"));
+    if (handler.canCancel())
+    {
+      JButton cancel = new JButton(
+              MessageManager.getString("action.cancel"));
       final IProgressIndicator us = this;
-      cancel.addActionListener(new ActionListener() {
+      cancel.addActionListener(new ActionListener()
+      {
 
         @Override
-        public void actionPerformed(ActionEvent e) {
+        public void actionPerformed(ActionEvent e)
+        {
           handler.cancelActivity(id);
-          us.setProgressBar(MessageManager.formatMessage("label.cancelled_params",
-              new Object[] { ((JLabel) progressPanel.getComponent(0)).getText() }), id);
+          us.setProgressBar(MessageManager
+                  .formatMessage("label.cancelled_params", new Object[]
+                  { ((JLabel) progressPanel.getComponent(0)).getText() }),
+                  id);
         }
       });
       progressPanel.add(cancel, BorderLayout.EAST);
@@ -2131,25 +2592,33 @@ public class Desktop extends jalview.jbgui.GDesktop
    * @return true if any progress bars are still active
    */
   @Override
-  public boolean operationInProgress() {
-    if (progressBars != null && progressBars.size() > 0) {
+  public boolean operationInProgress()
+  {
+    if (progressBars != null && progressBars.size() > 0)
+    {
       return true;
     }
     return false;
   }
 
   /**
-   * This will return the first AlignFrame holding the given viewport instance. It
-   * will break if there are more than one AlignFrames viewing a particular av.
+   * This will return the first AlignFrame holding the given viewport instance.
+   * It will break if there are more than one AlignFrames viewing a particular
+   * av.
    * 
    * @param viewport
    * @return alignFrame for viewport
    */
-  public static AlignFrame getAlignFrameFor(AlignViewportI viewport) {
-    if (desktop != null) {
-      AlignmentPanel[] aps = getAlignmentPanels(viewport.getSequenceSetId());
-      for (int panel = 0; aps != null && panel < aps.length; panel++) {
-        if (aps[panel] != null && aps[panel].av == viewport) {
+  public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
+  {
+    if (getDesktopPane() != null)
+    {
+      AlignmentPanel[] aps = getAlignmentPanels(
+              viewport.getSequenceSetId());
+      for (int panel = 0; aps != null && panel < aps.length; panel++)
+      {
+        if (aps[panel] != null && aps[panel].av == viewport)
+        {
           return aps[panel].alignFrame;
         }
       }
@@ -2157,7 +2626,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     return null;
   }
 
-  public VamsasApplication getVamsasApplication() {
+  public VamsasApplication getVamsasApplication()
+  {
     // TODO: JAL-3311 remove remaining code from Jalview relating to VAMSAS
     return null;
 
@@ -2173,7 +2643,8 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @return inBatchMode
    */
-  public boolean isInBatchMode() {
+  public boolean isInBatchMode()
+  {
     return inBatchMode;
   }
 
@@ -2182,66 +2653,59 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param inBatchMode
    */
-  public void setInBatchMode(boolean inBatchMode) {
+  public void setInBatchMode(boolean inBatchMode)
+  {
     this.inBatchMode = inBatchMode;
   }
 
-  /**
-   * start service discovery and wait till it is done
-   */
-  public void startServiceDiscovery() {
+  public void startServiceDiscovery()
+  {
     startServiceDiscovery(false);
   }
 
-  /**
-   * start service discovery threads - blocking or non-blocking
-   * 
-   * @param blocking
-   */
-  public void startServiceDiscovery(boolean blocking) {
-    startServiceDiscovery(blocking, false);
-  }
-
-  /**
-   * start service discovery threads
-   * 
-   * @param blocking                             - false means call returns
-   *                                             immediately
-   * @param ignore_SHOW_JWS2_SERVICES_preference - when true JABA services are
-   *                                             discovered regardless of user's
-   *                                             JWS2 discovery preference setting
-   */
-  public void startServiceDiscovery(boolean blocking, boolean ignore_SHOW_JWS2_SERVICES_preference) {
-    boolean alive = true;
-    Thread t0 = null, t1 = null, t2 = null;
+  public void startServiceDiscovery(boolean blocking)
+  {
+    System.out.println("Starting service discovery");
+    var tasks = new ArrayList<Future<?>>();
     // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
-    if (true) {
+
+    System.out.println("loading services");
+    
+    /** @j2sIgnore */
+    {
       // todo: changesupport handlers need to be transferred
-      if (discoverer == null) {
-        discoverer = new jalview.ws.jws1.Discoverer();
+      if (discoverer == null)
+      {
+        discoverer = jalview.ws.jws1.Discoverer.getInstance();
         // register PCS handler for desktop.
         discoverer.addPropertyChangeListener(changeSupport);
       }
       // JAL-940 - disabled JWS1 service configuration - always start discoverer
       // until we phase out completely
-      (t0 = new Thread(discoverer)).start();
+      var f = new FutureTask<Void>(discoverer, null);
+      new Thread(f).start();
+      tasks.add(f);
     }
 
-    if (ignore_SHOW_JWS2_SERVICES_preference || Cache.getDefault("SHOW_JWS2_SERVICES", true)) {
-      t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().startDiscoverer(changeSupport);
+    if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
+    {
+      tasks.add(jalview.ws.jws2.Jws2Discoverer.getInstance().startDiscoverer());
     }
-    Thread t3 = null;
+    if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
     {
-      // TODO: do rest service discovery
+      tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer());
     }
-    if (blocking) {
-      while (alive) {
-        try {
-          Thread.sleep(15);
-        } catch (Exception e) {
+    if (blocking)
+    {
+      for (Future<?> task : tasks) {
+        try
+        {
+          // block until all discovery tasks are done
+          task.get();
+        } catch (Exception e)
+        {
+          e.printStackTrace();
         }
-        alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive()) || (t3 != null && t3.isAlive())
-            || (t0 != null && t0.isAlive());
       }
     }
   }
@@ -2251,50 +2715,72 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param evt
    */
-  protected void JalviewServicesChanged(PropertyChangeEvent evt) {
-    if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector) {
-      final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer().getErrorMessages();
-      if (ermsg != null) {
-        if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true)) {
-          if (serviceChangedDialog == null) {
+  protected void JalviewServicesChanged(PropertyChangeEvent evt)
+  {
+    if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
+    {
+      final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer
+          .getInstance();
+      final String ermsg = discoverer.getErrorMessages();
+      // CONFLICT:ALT:?     final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
+      if (ermsg != null)
+      {
+        if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
+        {
+          if (serviceChangedDialog == null)
+          {
             // only run if we aren't already displaying one of these.
-            addDialogThread(serviceChangedDialog = new Runnable() {
+            addDialogThread(serviceChangedDialog = new Runnable()
+            {
               @Override
-              public void run() {
+              public void run()
+              {
 
                 /*
                  * JalviewDialog jd =new JalviewDialog() {
                  * 
-                 * @Override protected void cancelPressed() { // TODO Auto-generated method stub
+                 * @Override protected void cancelPressed() { // TODO
+                 * Auto-generated method stub
                  * 
-                 * }@Override protected void okPressed() { // TODO Auto-generated method stub
+                 * }@Override protected void okPressed() { // TODO
+                 * Auto-generated method stub
                  * 
-                 * }@Override protected void raiseClosed() { // TODO Auto-generated method stub
+                 * }@Override protected void raiseClosed() { // TODO
+                 * Auto-generated method stub
                  * 
-                 * } }; jd.initDialogFrame(new JLabel("<html><table width=\"450\"><tr><td>" +
-                 * ermsg +
+                 * } }; jd.initDialogFrame(new
+                 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
                  * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
                  * + " or mis-configured HTTP proxy settings.<br/>" +
-                 * "Check the <em>Connections</em> and <em>Web services</em> tab of the" +
-                 * " Tools->Preferences dialog box to change them.</td></tr></table></html>" ),
-                 * true, true, "Web Service Configuration Problem", 450, 400);
+                 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
+                 * +
+                 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
+                 * ), true, true, "Web Service Configuration Problem", 450,
+                 * 400);
                  * 
                  * jd.waitForInput();
                  */
-                JvOptionPane.showConfirmDialog(Desktop.desktop,
-                    new JLabel("<html><table width=\"450\"><tr><td>" + ermsg + "</td></tr></table>"
-                        + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
-                        + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
-                        + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
-                        + " Tools->Preferences dialog box to change them.</p></html>"),
-                    "Web Service Configuration Problem", JvOptionPane.DEFAULT_OPTION, JvOptionPane.ERROR_MESSAGE);
+                JvOptionPane.showConfirmDialog(desktopPane,
+                        new JLabel("<html><table width=\"450\"><tr><td>"
+                                + ermsg + "</td></tr></table>"
+                                + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
+                                + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
+                                + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
+                                + " Tools->Preferences dialog box to change them.</p></html>"),
+                        "Web Service Configuration Problem",
+                        JvOptionPane.DEFAULT_OPTION,
+                        JvOptionPane.ERROR_MESSAGE);
                 serviceChangedDialog = null;
 
               }
             });
           }
-        } else {
-          Cache.log.error("Errors reported by JABA discovery service. Check web services preferences.\n" + ermsg);
+        }
+        else
+        {
+          Cache.log.error(
+                  "Errors reported by JABA discovery service. Check web services preferences.\n"
+                          + ermsg);
         }
       }
     }
@@ -2309,34 +2795,47 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param url
    */
-  public static void showUrl(final String url) {
-    showUrl(url, Desktop.instance);
+  public static void showUrl(final String url)
+  {
+    showUrl(url, getInstance());
   }
 
   /**
    * Like showUrl but allows progress handler to be specified
    * 
    * @param url
-   * @param progress (null) or object implementing IProgressIndicator
+   * @param progress
+   *          (null) or object implementing IProgressIndicator
    */
-  public static void showUrl(final String url, final IProgressIndicator progress) {
-    new Thread(new Runnable() {
+  public static void showUrl(final String url,
+          final IProgressIndicator progress)
+  {
+    new Thread(new Runnable()
+    {
       @Override
-      public void run() {
-        try {
-          if (progress != null) {
-            progress.setProgressBar(MessageManager.formatMessage("status.opening_params", new Object[] { url }),
-                this.hashCode());
+      public void run()
+      {
+        try
+        {
+          if (progress != null)
+          {
+            progress.setProgressBar(MessageManager
+                    .formatMessage("status.opening_params", new Object[]
+                    { url }), this.hashCode());
           }
           jalview.util.BrowserLauncher.openURL(url);
-        } catch (Exception ex) {
-          JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-              MessageManager.getString("label.web_browser_not_found_unix"),
-              MessageManager.getString("label.web_browser_not_found"), JvOptionPane.WARNING_MESSAGE);
+        } catch (Exception ex)
+        {
+          JvOptionPane.showInternalMessageDialog(getDesktopPane(),
+                  MessageManager
+                          .getString("label.web_browser_not_found_unix"),
+                  MessageManager.getString("label.web_browser_not_found"),
+                  JvOptionPane.WARNING_MESSAGE);
 
           ex.printStackTrace();
         }
-        if (progress != null) {
+        if (progress != null)
+        {
           progress.setProgressBar(null, this.hashCode());
         }
       }
@@ -2345,8 +2844,10 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static WsParamSetManager wsparamManager = null;
 
-  public static ParamManager getUserParameterStore() {
-    if (wsparamManager == null) {
+  public static ParamManager getUserParameterStore()
+  {
+    if (wsparamManager == null)
+    {
       wsparamManager = new WsParamSetManager();
     }
     return wsparamManager;
@@ -2357,18 +2858,27 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param e
    */
-  public static void hyperlinkUpdate(HyperlinkEvent e) {
-    if (e.getEventType() == EventType.ACTIVATED) {
+  public static void hyperlinkUpdate(HyperlinkEvent e)
+  {
+    if (e.getEventType() == EventType.ACTIVATED)
+    {
       String url = null;
-      try {
+      try
+      {
         url = e.getURL().toString();
-        Desktop.showUrl(url);
-      } catch (Exception x) {
-        if (url != null) {
-          if (Cache.log != null) {
+        showUrl(url);
+      } catch (Exception x)
+      {
+        if (url != null)
+        {
+          if (Cache.log != null)
+          {
             Cache.log.error("Couldn't handle string " + url + " as a URL.");
-          } else {
-            System.err.println("Couldn't handle string " + url + " as a URL.");
+          }
+          else
+          {
+            System.err.println(
+                    "Couldn't handle string " + url + " as a URL.");
           }
         }
         // ignore any exceptions due to dud links.
@@ -2399,29 +2909,39 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param prompter
    */
-  public void addDialogThread(final Runnable prompter) {
-    dialogExecutor.submit(new Runnable() {
+  public void addDialogThread(final Runnable prompter)
+  {
+    dialogExecutor.submit(new Runnable()
+    {
       @Override
-      public void run() {
-        if (dialogPause) {
-          try {
+      public void run()
+      {
+        if (dialogPause)
+        {
+          try
+          {
             block.acquire();
-          } catch (InterruptedException x) {
+          } catch (InterruptedException x)
+          {
           }
         }
-        if (instance == null) {
+        if (Jalview.isHeadlessMode())
+        {
           return;
         }
-        try {
+        try
+        {
           SwingUtilities.invokeAndWait(prompter);
-        } catch (Exception q) {
+        } catch (Exception q)
+        {
           Cache.log.warn("Unexpected Exception in dialog thread.", q);
         }
       }
     });
   }
 
-  public void startDialogQueue() {
+  public void startDialogQueue()
+  {
     // set the flag so we don't pause waiting for another permit and semaphore
     // the current task to begin
     dialogPause = false;
@@ -2438,53 +2958,65 @@ public class Desktop extends jalview.jbgui.GDesktop
    * </pre>
    */
   @Override
-  protected void snapShotWindow_actionPerformed(ActionEvent e) {
+  protected void snapShotWindow_actionPerformed(ActionEvent e)
+  {
     // currently the menu option to do this is not shown
     invalidate();
 
     int width = getWidth();
     int height = getHeight();
-    File of = new File("Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
-    ImageWriterI writer = new ImageWriterI() {
+    File of = new File(
+            "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
+    ImageWriterI writer = new ImageWriterI()
+    {
       @Override
-      public void exportImage(Graphics g) throws Exception {
+      public void exportImage(Graphics g) throws Exception
+      {
         paintAll(g);
-        Cache.log.info("Successfully written snapshot to file " + of.getAbsolutePath());
+        Cache.log.info("Successfully written snapshot to file "
+                + of.getAbsolutePath());
       }
     };
     String title = "View of desktop";
-    ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS, title);
+    ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
+            title);
     exporter.doExport(of, this, width, height, title);
   }
 
   /**
    * Explode the views in the given SplitFrame into separate SplitFrame windows.
-   * This respects (remembers) any previous 'exploded geometry' i.e. the size and
-   * location last time the view was expanded (if any). However it does not
+   * This respects (remembers) any previous 'exploded geometry' i.e. the size
+   * and location last time the view was expanded (if any). However it does not
    * remember the split pane divider location - this is set to match the
    * 'exploding' frame.
    * 
    * @param sf
    */
-  public void explodeViews(SplitFrame sf) {
+  public void explodeViews(SplitFrame sf)
+  {
     AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
     AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
-    List<? extends AlignmentViewPanel> topPanels = oldTopFrame.getAlignPanels();
-    List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame.getAlignPanels();
+    List<? extends AlignmentViewPanel> topPanels = oldTopFrame
+            .getAlignPanels();
+    List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
+            .getAlignPanels();
     int viewCount = topPanels.size();
-    if (viewCount < 2) {
+    if (viewCount < 2)
+    {
       return;
     }
 
     /*
-     * Processing in reverse order works, forwards order leaves the first panels not
-     * visible. I don't know why!
+     * Processing in reverse order works, forwards order leaves the first panels
+     * not visible. I don't know why!
      */
-    for (int i = viewCount - 1; i >= 0; i--) {
+    for (int i = viewCount - 1; i >= 0; i--)
+    {
       /*
-       * Make new top and bottom frames. These take over the respective AlignmentPanel
-       * objects, including their AlignmentViewports, so the cdna/protein
-       * relationships between the viewports is carried over to the new split frames.
+       * Make new top and bottom frames. These take over the respective
+       * AlignmentPanel objects, including their AlignmentViewports, so the
+       * cdna/protein relationships between the viewports is carried over to the
+       * new split frames.
        * 
        * explodedGeometry holds the (x, y) position of the previously exploded
        * SplitFrame, and the (width, height) of the AlignFrame component
@@ -2493,8 +3025,10 @@ public class Desktop extends jalview.jbgui.GDesktop
       AlignFrame newTopFrame = new AlignFrame(topPanel);
       newTopFrame.setSize(oldTopFrame.getSize());
       newTopFrame.setVisible(true);
-      Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport()).getExplodedGeometry();
-      if (geometry != null) {
+      Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
+              .getExplodedGeometry();
+      if (geometry != null)
+      {
         newTopFrame.setSize(geometry.getSize());
       }
 
@@ -2502,23 +3036,27 @@ public class Desktop extends jalview.jbgui.GDesktop
       AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
       newBottomFrame.setSize(oldBottomFrame.getSize());
       newBottomFrame.setVisible(true);
-      geometry = ((AlignViewport) bottomPanel.getAlignViewport()).getExplodedGeometry();
-      if (geometry != null) {
+      geometry = ((AlignViewport) bottomPanel.getAlignViewport())
+              .getExplodedGeometry();
+      if (geometry != null)
+      {
         newBottomFrame.setSize(geometry.getSize());
       }
 
       topPanel.av.setGatherViewsHere(false);
       bottomPanel.av.setGatherViewsHere(false);
-      JInternalFrame splitFrame = new SplitFrame(newTopFrame, newBottomFrame);
-      if (geometry != null) {
+      JInternalFrame splitFrame = new SplitFrame(newTopFrame,
+              newBottomFrame);
+      if (geometry != null)
+      {
         splitFrame.setLocation(geometry.getLocation());
       }
-      Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
+      addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
     }
 
     /*
-     * Clear references to the panels (now relocated in the new SplitFrames) before
-     * closing the old SplitFrame.
+     * Clear references to the panels (now relocated in the new SplitFrames)
+     * before closing the old SplitFrame.
      */
     topPanels.clear();
     bottomPanels.clear();
@@ -2532,7 +3070,8 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @param source
    */
-  public void gatherViews(GSplitFrame source) {
+  public void gatherViews(GSplitFrame source)
+  {
     /*
      * special handling of explodedGeometry for a view within a SplitFrame: - it
      * holds the (x, y) position of the enclosing SplitFrame, and the (width,
@@ -2540,38 +3079,46 @@ public class Desktop extends jalview.jbgui.GDesktop
      */
     AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
     AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
-    myTopFrame.viewport.setExplodedGeometry(
-        new Rectangle(source.getX(), source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
-    myBottomFrame.viewport.setExplodedGeometry(
-        new Rectangle(source.getX(), source.getY(), myBottomFrame.getWidth(), myBottomFrame.getHeight()));
+    myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
+            source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
+    myBottomFrame.viewport
+            .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
+                    myBottomFrame.getWidth(), myBottomFrame.getHeight()));
     myTopFrame.viewport.setGatherViewsHere(true);
     myBottomFrame.viewport.setGatherViewsHere(true);
     String topViewId = myTopFrame.viewport.getSequenceSetId();
     String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
 
-    JInternalFrame[] frames = desktop.getAllFrames();
-    for (JInternalFrame frame : frames) {
-      if (frame instanceof SplitFrame && frame != source) {
+    JInternalFrame[] frames = desktopPane.getAllFrames();
+    for (JInternalFrame frame : frames)
+    {
+      if (frame instanceof SplitFrame && frame != source)
+      {
         SplitFrame sf = (SplitFrame) frame;
         AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
         AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
         boolean gatherThis = false;
-        for (int a = 0; a < topFrame.alignPanels.size(); a++) {
+        for (int a = 0; a < topFrame.alignPanels.size(); a++)
+        {
           AlignmentPanel topPanel = topFrame.alignPanels.get(a);
           AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
           if (topViewId.equals(topPanel.av.getSequenceSetId())
-              && bottomViewId.equals(bottomPanel.av.getSequenceSetId())) {
+                  && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
+          {
             gatherThis = true;
             topPanel.av.setGatherViewsHere(false);
             bottomPanel.av.setGatherViewsHere(false);
-            topPanel.av.setExplodedGeometry(new Rectangle(sf.getLocation(), topFrame.getSize()));
-            bottomPanel.av.setExplodedGeometry(new Rectangle(sf.getLocation(), bottomFrame.getSize()));
+            topPanel.av.setExplodedGeometry(
+                    new Rectangle(sf.getLocation(), topFrame.getSize()));
+            bottomPanel.av.setExplodedGeometry(
+                    new Rectangle(sf.getLocation(), bottomFrame.getSize()));
             myTopFrame.addAlignmentPanel(topPanel, false);
             myBottomFrame.addAlignmentPanel(bottomPanel, false);
           }
         }
 
-        if (gatherThis) {
+        if (gatherThis)
+        {
           topFrame.getAlignPanels().clear();
           bottomFrame.getAlignPanels().clear();
           sf.close();
@@ -2585,7 +3132,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     myTopFrame.setDisplayedView(myTopFrame.alignPanel);
   }
 
-  public static groovy.ui.Console getGroovyConsole() {
+  public static groovy.ui.Console getGroovyConsole()
+  {
     return groovyConsole;
   }
 
@@ -2594,88 +3142,148 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * TODO refactor to desktop utilities class
    * 
-   * @param files     - Data source strings extracted from the drop event
-   * @param protocols - protocol for each data source extracted from the drop
-   *                  event
-   * @param evt       - the drop event
-   * @param t         - the payload from the drop event
+   * @param files
+   *          - Data source strings extracted from the drop event
+   * @param protocols
+   *          - protocol for each data source extracted from the drop event
+   * @param evt
+   *          - the drop event
+   * @param t
+   *          - the payload from the drop event
    * @throws Exception
    */
-  public static void transferFromDropTarget(List<Object> files, List<DataSourceType> protocols, DropTargetDropEvent evt,
-      Transferable t) throws Exception {
-
-    DataFlavor uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String"), urlFlavour = null;
-    try {
-      urlFlavour = new DataFlavor("application/x-java-url; class=java.net.URL");
-    } catch (ClassNotFoundException cfe) {
+  @SuppressWarnings("unchecked")
+  public static void transferFromDropTarget(List<Object> files,
+          List<DataSourceType> protocols, DropTargetDropEvent evt,
+          Transferable t) throws Exception
+  {
+
+    // BH 2018 changed List<String> to List<Object> to allow for File from
+    // SwingJS
+
+    // DataFlavor[] flavors = t.getTransferDataFlavors();
+    // for (int i = 0; i < flavors.length; i++) {
+    // if (flavors[i].isFlavorJavaFileListType()) {
+    // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+    // List<File> list = (List<File>) t.getTransferData(flavors[i]);
+    // for (int j = 0; j < list.size(); j++) {
+    // File file = (File) list.get(j);
+    // byte[] data = getDroppedFileBytes(file);
+    // fileName.setText(file.getName() + " - " + data.length + " " +
+    // evt.getLocation());
+    // JTextArea target = (JTextArea) ((DropTarget)
+    // evt.getSource()).getComponent();
+    // target.setText(new String(data));
+    // }
+    // dtde.dropComplete(true);
+    // return;
+    // }
+    //
+
+    DataFlavor uriListFlavor = new DataFlavor(
+            "text/uri-list;class=java.lang.String"), urlFlavour = null;
+    try
+    {
+      urlFlavour = new DataFlavor(
+              "application/x-java-url; class=java.net.URL");
+    } catch (ClassNotFoundException cfe)
+    {
       Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
     }
 
-    if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour)) {
+    if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
+    {
 
-      try {
+      try
+      {
         java.net.URL url = (URL) t.getTransferData(urlFlavour);
         // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
         // means url may be null.
-        if (url != null) {
+        if (url != null)
+        {
           protocols.add(DataSourceType.URL);
           files.add(url.toString());
-          Cache.log.debug("Drop handled as URL dataflavor " + files.get(files.size() - 1));
+          Cache.log.debug("Drop handled as URL dataflavor "
+                  + files.get(files.size() - 1));
           return;
-        } else {
-          if (Platform.isAMacAndNotJS()) {
-            System.err.println("Please ignore plist error - occurs due to problem with java 8 on OSX");
+        }
+        else
+        {
+          if (Platform.isAMacAndNotJS())
+          {
+            System.err.println(
+                    "Please ignore plist error - occurs due to problem with java 8 on OSX");
           }
         }
-      } catch (Throwable ex) {
+      } catch (Throwable ex)
+      {
         Cache.log.debug("URL drop handler failed.", ex);
       }
     }
-    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+    if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+    {
       // Works on Windows and MacOSX
       Cache.log.debug("Drop handled as javaFileListFlavor");
-      for (Object file : (List) t.getTransferData(DataFlavor.javaFileListFlavor)) {
+      for (File file : (List<File>) t
+              .getTransferData(DataFlavor.javaFileListFlavor))
+      {
         files.add(file);
         protocols.add(DataSourceType.FILE);
       }
-    } else {
+    }
+    else
+    {
       // Unix like behaviour
       boolean added = false;
       String data = null;
-      if (t.isDataFlavorSupported(uriListFlavor)) {
+      if (t.isDataFlavorSupported(uriListFlavor))
+      {
         Cache.log.debug("Drop handled as uriListFlavor");
         // This is used by Unix drag system
         data = (String) t.getTransferData(uriListFlavor);
       }
-      if (data == null) {
+      if (data == null)
+      {
         // fallback to text: workaround - on OSX where there's a JVM bug
         Cache.log.debug("standard URIListFlavor failed. Trying text");
         // try text fallback
-        DataFlavor textDf = new DataFlavor("text/plain;class=java.lang.String");
-        if (t.isDataFlavorSupported(textDf)) {
+        DataFlavor textDf = new DataFlavor(
+                "text/plain;class=java.lang.String");
+        if (t.isDataFlavorSupported(textDf))
+        {
           data = (String) t.getTransferData(textDf);
         }
 
-        Cache.log.debug("Plain text drop content returned " + (data == null ? "Null - failed" : data));
+        Cache.log.debug("Plain text drop content returned "
+                + (data == null ? "Null - failed" : data));
 
       }
-      if (data != null) {
-        while (protocols.size() < files.size()) {
-          Cache.log.debug("Adding missing FILE protocol for " + files.get(protocols.size()));
+      if (data != null)
+      {
+        while (protocols.size() < files.size())
+        {
+          Cache.log.debug("Adding missing FILE protocol for "
+                  + files.get(protocols.size()));
           protocols.add(DataSourceType.FILE);
         }
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(data, "\r\n"); st.hasMoreTokens();) {
+        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+                data, "\r\n"); st.hasMoreTokens();)
+        {
           added = true;
           String s = st.nextToken();
-          if (s.startsWith("#")) {
+          if (s.startsWith("#"))
+          {
             // the line is a comment (as per the RFC 2483)
             continue;
           }
           java.net.URI uri = new java.net.URI(s);
-          if (uri.getScheme().toLowerCase(Locale.ROOT).startsWith("http")) {
+          if (uri.getScheme().toLowerCase().startsWith("http"))
+          {
             protocols.add(DataSourceType.URL);
             files.add(uri.toString());
-          } else {
+          }
+          else
+          {
             // otherwise preserve old behaviour: catch all for file objects
             java.io.File file = new java.io.File(uri);
             protocols.add(DataSourceType.FILE);
@@ -2684,46 +3292,69 @@ public class Desktop extends jalview.jbgui.GDesktop
         }
       }
 
-      if (Cache.log.isDebugEnabled()) {
-        if (data == null || !added) {
+      if (Cache.log.isDebugEnabled())
+      {
+        if (data == null || !added)
+        {
 
-          if (t.getTransferDataFlavors() != null && t.getTransferDataFlavors().length > 0) {
-            Cache.log.debug("Couldn't resolve drop data. Here are the supported flavors:");
-            for (DataFlavor fl : t.getTransferDataFlavors()) {
-              Cache.log.debug("Supported transfer dataflavor: " + fl.toString());
+          if (t.getTransferDataFlavors() != null
+                  && t.getTransferDataFlavors().length > 0)
+          {
+            Cache.log.debug(
+                    "Couldn't resolve drop data. Here are the supported flavors:");
+            for (DataFlavor fl : t.getTransferDataFlavors())
+            {
+              Cache.log.debug(
+                      "Supported transfer dataflavor: " + fl.toString());
               Object df = t.getTransferData(fl);
-              if (df != null) {
+              if (df != null)
+              {
                 Cache.log.debug("Retrieves: " + df);
-              } else {
+              }
+              else
+              {
                 Cache.log.debug("Retrieved nothing");
               }
             }
-          } else {
-            Cache.log.debug("Couldn't resolve dataflavor for drop: " + t.toString());
+          }
+          else
+          {
+            Cache.log.debug("Couldn't resolve dataflavor for drop: "
+                    + t.toString());
           }
         }
       }
     }
-    if (Platform.isWindowsAndNotJS()) {
+    if (Platform.isWindowsAndNotJS())
+    {
       Cache.log.debug("Scanning dropped content for Windows Link Files");
 
       // resolve any .lnk files in the file drop
-      for (int f = 0; f < files.size(); f++) {
-        String source = files.get(f).toString().toLowerCase(Locale.ROOT);
+      for (int f = 0; f < files.size(); f++)
+      {
+        String source = files.get(f).toString().toLowerCase();
         if (protocols.get(f).equals(DataSourceType.FILE)
-            && (source.endsWith(".lnk") || source.endsWith(".url") || source.endsWith(".site"))) {
-          try {
+                && (source.endsWith(".lnk") || source.endsWith(".url")
+                        || source.endsWith(".site")))
+        {
+          try
+          {
             Object obj = files.get(f);
-            File lf = (obj instanceof File ? (File) obj : new File((String) obj));
+            File lf = (obj instanceof File ? (File) obj
+                    : new File((String) obj));
             // process link file to get a URL
             Cache.log.debug("Found potential link file: " + lf);
             WindowsShortcut wscfile = new WindowsShortcut(lf);
             String fullname = wscfile.getRealFilename();
             protocols.set(f, FormatAdapter.checkProtocol(fullname));
             files.set(f, fullname);
-            Cache.log.debug("Parsed real filename " + fullname + " to extract protocol: " + protocols.get(f));
-          } catch (Exception ex) {
-            Cache.log.error("Couldn't parse " + files.get(f) + " as a link file.", ex);
+            Cache.log.debug("Parsed real filename " + fullname
+                    + " to extract protocol: " + protocols.get(f));
+          } catch (Exception ex)
+          {
+            Cache.log.error(
+                    "Couldn't parse " + files.get(f) + " as a link file.",
+                    ex);
           }
         }
       }
@@ -2735,30 +3366,40 @@ public class Desktop extends jalview.jbgui.GDesktop
    * depending on the state of the controlling menu item
    */
   @Override
-  protected void showExperimental_actionPerformed(boolean selected) {
+  protected void showExperimental_actionPerformed(boolean selected)
+  {
     Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
   }
 
   /**
-   * Answers a (possibly empty) list of any structure viewer frames (currently for
-   * either Jmol or Chimera) which are currently open. This may optionally be
-   * restricted to viewers of a specified class, or viewers linked to a specified
-   * alignment panel.
+   * Answers a (possibly empty) list of any structure viewer frames (currently
+   * for either Jmol or Chimera) which are currently open. This may optionally
+   * be restricted to viewers of a specified class, or viewers linked to a
+   * specified alignment panel.
    * 
-   * @param apanel               if not null, only return viewers linked to this
-   *                             panel
-   * @param structureViewerClass if not null, only return viewers of this class
+   * @param apanel
+   *          if not null, only return viewers linked to this panel
+   * @param structureViewerClass
+   *          if not null, only return viewers of this class
    * @return
    */
-  public List<StructureViewerBase> getStructureViewers(AlignmentPanel apanel,
-      Class<? extends StructureViewerBase> structureViewerClass) {
+  public List<StructureViewerBase> getStructureViewers(
+          AlignmentPanel apanel,
+          Class<? extends StructureViewerBase> structureViewerClass)
+  {
     List<StructureViewerBase> result = new ArrayList<>();
-    JInternalFrame[] frames = Desktop.instance.getAllFrames();
+    JInternalFrame[] frames = getAllFrames();
 
-    for (JInternalFrame frame : frames) {
-      if (frame instanceof StructureViewerBase) {
-        if (structureViewerClass == null || structureViewerClass.isInstance(frame)) {
-          if (apanel == null || ((StructureViewerBase) frame).isLinkedWith(apanel)) {
+    for (JInternalFrame frame : frames)
+    {
+      if (frame instanceof StructureViewerBase)
+      {
+        if (structureViewerClass == null
+                || structureViewerClass.isInstance(frame))
+        {
+          if (apanel == null
+                  || ((StructureViewerBase) frame).isLinkedWith(apanel))
+          {
             result.add((StructureViewerBase) frame);
           }
         }