Index: /main/trunk/gli/src/org/greenstone/gatherer/remote/ActionQueue.java
===================================================================
--- /main/trunk/gli/src/org/greenstone/gatherer/remote/ActionQueue.java	(revision 34233)
+++ /main/trunk/gli/src/org/greenstone/gatherer/remote/ActionQueue.java	(revision 34234)
@@ -79,17 +79,4 @@
     }
     
-    // We often end up with giant blotted remote build error messages when things blow up
-    // These messages appear in pop ups that take up the entire screen and we can't even see the OK button
-    // This method therefore adds a scrollPane around error messages when displaying them.
-    // https://alvinalexander.com/java/joptionpane-showmessagedialog-example-scrolling/
-    private JScrollPane getMsgInScrollPane(String msg) {
-	// create a JTextArea
-	JTextArea textArea = new JTextArea(20, 70);
-	textArea.setText(msg);
-	textArea.setEditable(false);
-	// wrap a scrollpane around message
-	JScrollPane scrollPane = new JScrollPane(textArea);
-	return scrollPane;
-    }
     
     synchronized public void addAction(RemoteGreenstoneServerAction remote_greenstone_server_action)
@@ -161,6 +148,5 @@
 		    DebugStream.printStackTrace(exception);
 		}
-		JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error", exception.getMessage()));
-		JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE);
+		RemoteErrorPopup.invokeLater(exception.getMessage());
 		remote_greenstone_server_action.processed_successfully = false;			
 	    }
@@ -170,16 +156,10 @@
 		exit = true;
 		DebugStream.printStackTrace(exception);
-		JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error", 
-							     "No gliserver.pl found. " + exception.getMessage()));
-		JOptionPane.showMessageDialog(Gatherer.g_man, 
-					      scrollPane, 
-					      Dictionary.get("RemoteGreenstoneServer.Error_Title"), 
-					      JOptionPane.ERROR_MESSAGE);
+		RemoteErrorPopup.invokeLater("No gliserver.pl found. " + exception.getMessage());
 		remote_greenstone_server_action.processed_successfully = false;
 	    }
 	    catch (Exception exception) {
 		DebugStream.printStackTrace(exception);
-		JScrollPane scrollPane = getMsgInScrollPane(Dictionary.get("RemoteGreenstoneServer.Error", exception.getMessage()));
-		JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE);
+		RemoteErrorPopup.invokeLater(exception.getMessage());
 		remote_greenstone_server_action.processed_successfully = false;
 	    }
@@ -208,3 +188,60 @@
 	}
     }
+
+    
+    // When deadlock, referred to in Kathy's commit comments as stalemate, occurs during a RemoteGS threaded
+    // task run on a queue, and this task is a GUI one and on the GUI thread, such as launching GEMS from the
+    // MetadataSetManager to create/edit a metadata set, any remote errors that then cause error dialogs to
+    // pop up result in a deadlock between the widgets since there's waiting going on for the first widget.
+    // This prevents the second widget from showing or working right, as both are on the same (GUI) thread.
+    // As end result, client-GLI freezes.
+    // An example of such an error that caused an error message to popup resulting in a GUI deadlock was
+    // fixed in commit http://trac.greenstone.org/changeset/34232 (client-GLI > MetadataSetManager > GEMS)
+    // But in theory such a GUI deadlock could happen for as yet unfixed errors. It prevents us from even
+    // reading the error msg in the popup and delays debugging. What we need is to show the popup when
+    // the GUI thread is free, i.e. SwingUtilities.invokeLater() stuff.
+    // Private inner class RemoteErrorPopup deals with that. Refer to:
+    // - https://stackoverflow.com/questions/1595744/is-joptionpane-showmessagedialog-thread-safe
+    //   "JOptionPane does not document that it is thread safe, so you have to use invokeLater()."
+    //   Also contains SwingWorker-based idea for the GUI thread clash between OpenCollDialog and
+    // ProgressBar during automated Greenstone GUI testing.
+    // - https://stackoverflow.com/questions/13863713/which-thread-to-launch-joptionpane
+    // - https://www.codota.com/code/java/methods/javax.swing.JOptionPane/showMessageDialog
+    // - https://www.programcreek.com/java-api-examples/?class=javax.swing.SwingUtilities&method=invokeLater
+    private static class RemoteErrorPopup implements Runnable {
+
+	/** Custom static method to make a safely threaded popup easier to call */
+	public static void invokeLater(String msg) {
+	    SwingUtilities.invokeLater(new RemoteErrorPopup(msg));
+	}
+
+	
+	private String message;
+	
+	private RemoteErrorPopup(String msg) {
+	    message = msg;
+	}
+
+		
+	@Override
+	public void run() {
+	    
+	    String msg = Dictionary.get("RemoteGreenstoneServer.Error", message);
+
+	    // We often end up with giant bloated remote build error messages when things blow up
+	    // These messages appear in pop ups that take up the entire screen and we can't even see the OK button
+	    // The following therefore adds a scrollPane around error messages shown in showMessageDialog
+	    // https://alvinalexander.com/java/joptionpane-showmessagedialog-example-scrolling/
+	    JTextArea textArea = new JTextArea(20, 70);
+	    textArea.setText(msg);
+	    textArea.setEditable(false);
+	    // wrap a scrollpane around message
+	    JScrollPane scrollPane = new JScrollPane(textArea);	    
+	    
+	    JOptionPane.showMessageDialog(Gatherer.g_man, scrollPane, Dictionary.get("RemoteGreenstoneServer.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	}	
+    }
+    
 }
+
+
