changeset 1490:2cf2e3479d57

Fixed EDT hanging
author Jiri Vanek <jvanek@redhat.com>
date Mon, 01 Oct 2018 19:16:32 +0200
parents 5adcd54e9d3b
children 2cce11acb592
files AUTHORS ChangeLog netx/net/sourceforge/jnlp/GuiLaunchHandler.java netx/net/sourceforge/jnlp/JNLPSplashScreen.java netx/net/sourceforge/jnlp/Launcher.java netx/net/sourceforge/jnlp/about/AboutDialog.java netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java netx/net/sourceforge/jnlp/runtime/Boot.java netx/net/sourceforge/jnlp/runtime/HtmlBoot.java netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java netx/net/sourceforge/jnlp/security/SecurityDialog.java netx/net/sourceforge/jnlp/security/SecurityDialogs.java netx/net/sourceforge/jnlp/security/dialogs/ViwableDialog.java netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java netx/net/sourceforge/jnlp/splashscreen/impls/defaultsplashscreen2012/BasePainter.java netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java netx/net/sourceforge/jnlp/util/FileUtils.java netx/net/sourceforge/jnlp/util/logging/JavaConsole.java netx/net/sourceforge/swing/SwingUtils.java netx/net/sourceforge/swing/ThreadCheckingRepaintManager.java
diffstat 25 files changed, 576 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/AUTHORS	Mon Oct 01 19:08:34 2018 +0200
+++ b/AUTHORS	Mon Oct 01 19:16:32 2018 +0200
@@ -4,6 +4,7 @@
 Lillian Angel <langel@redhat.com>
 Andrew Azores <aazores@redhat.com>
 Deepak Bhole <dbhole@redhat.com>
+Laurent Bourgès <bourges.laurent@gmail.com>
 Adam Buchta <adbuch7@gmail.com>
 Ricardo Martín Camarero <rickyepoderi@yahoo.es>
 Marcin Cieslak <marcin.cieslak@gmail.com>
--- a/ChangeLog	Mon Oct 01 19:08:34 2018 +0200
+++ b/ChangeLog	Mon Oct 01 19:16:32 2018 +0200
@@ -1,3 +1,41 @@
+2018-10-01  Laurent Bourgès <bourges.laurent@gmail.com>
+
+	Fixed EDT hanging
+	* AUTHORS: added Laurent
+	* netx/net/sourceforge/jnlp/GuiLaunchHandler.java: invokeLater and invokeAndWait moved from SwingUtilities to the local wrapper SwingUtils.
+	Simplified splashscreen loading
+	* netx/net/sourceforge/jnlp/JNLPSplashScreen.java: called super and added name to the dialog
+	* netx/net/sourceforge/jnlp/Launcher.java: added log entry for main class loading. Highlighted usage of SwingUtilities on top SwingUtils
+	for this particular space
+	* netx/net/sourceforge/jnlp/about/AboutDialog.java: added name. InvokeLater and invokeAndWait moved from SwingUtilities to the 
+	local wrapper SwingUtils.
+	* netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java: reworked to work in SwingUtils.invokeAndWait. Added name.
+	* netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java: added name
+	* netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java: added name
+	* netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java: added top level setup for enabling SwingUtils debugging abilities
+	added log entry for main class loading. Highlighted usage of SwingUtilities on top SwingUtils for this particular space
+	* netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java: instead of invokeAndWait, used SwingUtils.callOnAppContext
+	* netx/net/sourceforge/jnlp/runtime/Boot.java: added top level setup for enabling SwingUtils debugging abilities
+	CertificateViwer moved to invokeAndWait. added log entry for main class loading. Highlighted usage of SwingUtilities instead
+	of SwingUtils for this particular case
+	* netx/net/sourceforge/jnlp/runtime/HtmlBoot.java: invokeLater and invokeAndWait moved from SwingUtilities to the local wrapper SwingUtils.
+	* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java: removed import of import javax.swing.JWindow
+	* netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java: direct call to JWindow().getOwner(), moved to  SwingUtils.getOrCreateWindowOwner.
+	Its existence doubtful
+	* netx/net/sourceforge/jnlp/security/SecurityDialog.java: installPanel moved to invokeAndWait
+	* netx/net/sourceforge/jnlp/security/SecurityDialogs.java: used SwingUtils instead of SwingUtilities, added name
+	* netx/net/sourceforge/jnlp/security/dialogs/ViwableDialog.java: swing ops moved to invokeAndWait
+	* netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java: calling Swingutils.setup, still all the same
+	* netx/net/sourceforge/jnlp/splashscreen/impls/defaultsplashscreen2012/BasePainter.java: still the same
+	* netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java: same - name, SwingUtils x SwingUtilities, and proper usage of invokes
+	* netx/net/sourceforge/jnlp/util/FileUtils.java: SwingUtils x SwingUtilities
+	* netx/net/sourceforge/jnlp/util/logging/JavaConsole.java: observable.notifyObservers moved to invokeLater and
+	and invoked only if observable.hasChanged
+	* netx/net/sourceforge/swing/SwingUtils.java: new class. Wrapper around most commonly used SwingUtilities calls. Add debugging bridge
+	property of icedtea-web.edt.debug set to true, can enable it on runtime.
+	* netx/net/sourceforge/swing/ThreadCheckingRepaintManager.java: Based on http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
+	debugging repaint manager
+
 2018-10-01  Fridrich Strba  <fridrich.strba@suse.com>
 
 	Added eternal java version detection
--- a/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Mon Oct 01 19:16:32 2018 +0200
@@ -37,10 +37,8 @@
 
 package net.sourceforge.jnlp;
 
-import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
-
-import javax.swing.SwingUtilities;
+import net.sourceforge.swing.SwingUtils;
 
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.cache.UpdatePolicy;
@@ -70,7 +68,7 @@
     @Override
     public void launchError(final LaunchException exception) {
         BasicExceptionDialog.willBeShown();
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
             @Override
             public void run() {
                 closeSplashScreen();
@@ -94,7 +92,7 @@
 
     @Override
     public void launchStarting(ApplicationInstance application) {
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
             @Override
             public void run() {
                 closeSplashScreen();
@@ -117,39 +115,17 @@
             resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, policy);
         }
         synchronized (mutex) {
-            try {
-                SwingUtilities.invokeAndWait(new Runnable() {
+            SwingUtils.invokeAndWait(new Runnable() {
 
-                    @Override
-                    public void run() {
-                        splashScreen = new JNLPSplashScreen(resourceTracker, file);
-                    }
-                });
-            } catch (InterruptedException ie) {
-                // Wait till splash screen is created
-                while (splashScreen == null);
-            } catch (InvocationTargetException ite) {
-                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ite);
-            }
-            try {
-                SwingUtilities.invokeAndWait(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        splashScreen.setSplashImageURL(splashImageURL);
-                    }
-                });
-            } catch (InterruptedException ie) {
-                // Wait till splash screen is created
-                while (!splashScreen.isSplashImageLoaded());
-            } catch (InvocationTargetException ite) {
-                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ite);
-            }
-
-
+                @Override
+                public void run() {
+                    splashScreen = new JNLPSplashScreen(resourceTracker, file);
+                    splashScreen.setSplashImageURL(splashImageURL);
+                }
+            });
         }
 
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
 
             @Override
             public void run() {
--- a/netx/net/sourceforge/jnlp/JNLPSplashScreen.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/JNLPSplashScreen.java	Mon Oct 01 19:16:32 2018 +0200
@@ -47,6 +47,7 @@
 import java.net.URL;
 import javax.imageio.ImageIO;
 import javax.swing.JDialog;
+import net.sourceforge.swing.SwingUtils;
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.splashscreen.SplashPanel;
 import net.sourceforge.jnlp.splashscreen.SplashUtils;
@@ -70,7 +71,9 @@
     private SplashPanel splash;
 
     public JNLPSplashScreen(ResourceTracker resourceTracker, final JNLPFile file) {
-
+        super();
+        this.setName("JNLPSplashScreen");
+        SwingUtils.info(this);
         setIconImages(ImageResources.INSTANCE.getApplicationImages());
 
         // If the JNLP file does not contain any icon images, the splash image
--- a/netx/net/sourceforge/jnlp/Launcher.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/Launcher.java	Mon Oct 01 19:16:32 2018 +0200
@@ -40,11 +40,11 @@
 import net.sourceforge.jnlp.services.InstanceExistsException;
 import net.sourceforge.jnlp.services.ServiceUtil;
 
-import javax.swing.SwingUtilities;
 import javax.swing.text.html.parser.ParserDelegator;
 import net.sourceforge.jnlp.splashscreen.SplashUtils;
 import net.sourceforge.jnlp.util.StreamUtils;
 import net.sourceforge.jnlp.util.logging.OutputController;
+import net.sourceforge.swing.SwingUtils;
 
 import sun.awt.SunToolkit;
 
@@ -549,12 +549,15 @@
                         R("LCantDetermineMainClassInfo")));
             }
 
+            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Starting application [" + mainName + "] ...");
+            
             Class<?> mainClass = app.getClassLoader().loadClass(mainName);
 
             Method main = mainClass.getMethod("main", new Class<?>[] { String[].class });
             String args[] = file.getApplication().getArguments();
 
-            SwingUtilities.invokeAndWait(new Runnable() {
+            // create EDT within application context:
+            SwingUtils.callOnAppContext(new Runnable() {
                 // dummy method to force Event Dispatch Thread creation
                 @Override
                 public void run() {
--- a/netx/net/sourceforge/jnlp/about/AboutDialog.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/about/AboutDialog.java	Mon Oct 01 19:16:32 2018 +0200
@@ -53,13 +53,13 @@
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JPanel;
-import javax.swing.SwingUtilities;
 import javax.swing.border.EmptyBorder;
 
 import net.sourceforge.jnlp.util.ScreenFinder;
 import net.sourceforge.jnlp.util.docprovider.TextsProvider;
 import net.sourceforge.jnlp.util.docprovider.formatters.formatters.HtmlFormatter;
 import net.sourceforge.jnlp.util.logging.OutputController;
+import net.sourceforge.swing.SwingUtils;
 
 public final class AboutDialog extends JPanel implements Runnable, ActionListener {
 
@@ -95,10 +95,11 @@
         super(new GridBagLayout());
         this.app = app;
         frame = new JDialog((Frame) null, R("AboutDialogueTabAbout") + " IcedTea-Web", modal);
+        frame.setName("AboutDialog");
+        SwingUtils.info(frame);
         frame.setContentPane(this);
         frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 
-
         aboutButton = new JButton( R("AboutDialogueTabAbout"));
         aboutButton.addActionListener(this);
 
@@ -267,7 +268,7 @@
     }
     
     public static void display(boolean modal, String app, ShowPage showPage) {
-        SwingUtilities.invokeLater(new AboutDialog(modal, app, showPage));
+        SwingUtils.invokeLater(new AboutDialog(modal, app, showPage));
     }
 }
 
--- a/netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java	Mon Oct 01 19:16:32 2018 +0200
@@ -26,6 +26,7 @@
 import javax.swing.*;
 import javax.swing.Timer;
 import javax.jnlp.*;
+import net.sourceforge.swing.SwingUtils;
 
 import net.sourceforge.jnlp.runtime.*;
 import net.sourceforge.jnlp.util.ImageResources;
@@ -106,39 +107,48 @@
      * @return donload service listener attached to this app. instance
      */
     @Override
-    public DownloadServiceListener getListener(ApplicationInstance app, String downloadName, URL resources[]) {
-        DownloadPanel result = new DownloadPanel(downloadName);
+    public DownloadServiceListener getListener(ApplicationInstance app, final String downloadName, final URL resources[]) {
+        final FutureResult<DownloadPanel> result = new FutureResult<DownloadPanel>() {
+            @Override
+            public void run() {
+                DownloadPanel result = new DownloadPanel(downloadName);
+
+                synchronized (dialogMutex) {
+                    if (dialog == null) {
+                        dialog = createDownloadIndicatorWindow(true);
+                    }
 
-        synchronized (dialogMutex) {
-            if (dialog == null) {
-                dialog = createDownloadIndicatorWindow(true);
-            }
+                    if (resources != null) {
+                        for (URL url : resources) {
+                            result.addProgressPanel(url, null);
+                        }
+                    }
 
-            if (resources != null) {
-                for (URL url : resources) {
-                    result.addProgressPanel(url, null);
-        
+                    dialog.getContentPane().add(result, vertical);
+                    dialog.pack();
+                    placeFrameToLowerRight();
+                    
+                    result.addComponentListener(new ComponentAdapter() {
+                        @Override
+                        public void componentResized(ComponentEvent e) {
+                            placeFrameToLowerRight();
+                        }
+                    });
+
+                    dialog.setVisible(true);
+
+                    setRef(result);
                 }
             }
-
-            dialog.getContentPane().add(result, vertical);
-            dialog.pack();
-            placeFrameToLowerRight();
-            result.addComponentListener(new ComponentAdapter() {
-                @Override
-                public void componentResized(ComponentEvent e) {
-                    placeFrameToLowerRight();
-                }
-            });
-
-            dialog.setVisible(true);
-
-            return result;
-        }
+        };
+        SwingUtils.invokeAndWait(result);
+        return result.getRef();
     }
 
      public static JDialog createDownloadIndicatorWindow(boolean undecorated) throws HeadlessException {
         JDialog f = new JDialog((JFrame)null, downloading + "...");
+        f.setName("DownloadIndicatorDialog");
+        SwingUtils.info(f);
         f.setUndecorated(undecorated);
         f.setIconImages(ImageResources.INSTANCE.getApplicationImages());
         f.getContentPane().setLayout(new GridBagLayout());
@@ -328,7 +338,7 @@
 
                 }
             };
-            SwingUtilities.invokeLater(r);
+            SwingUtils.invokeLater(r);
         }
 
         /**
@@ -474,4 +484,15 @@
         }
     };
 
+    static abstract class FutureResult<V> implements Runnable {
+        private V ref = null;
+
+        public V getRef() {
+            return ref;
+        }
+
+        public void setRef(V ref) {
+            this.ref = ref;
+        }
+    }
 }
--- a/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java	Mon Oct 01 19:16:32 2018 +0200
@@ -32,6 +32,7 @@
 import net.sourceforge.jnlp.runtime.Translator;
 import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.util.ScreenFinder;
+import net.sourceforge.swing.SwingUtils;
 
 /**
  * This dialog provides a means for user to edit more of the proxy settings.
@@ -55,6 +56,8 @@
      */
     public AdvancedProxySettingsDialog(DeploymentConfiguration config) {
         super((Frame) null, dialogTitle, true); // Don't need a parent.
+        this.setName("AdvancedProxySettingsDialog");
+        SwingUtils.info(this);
         setIconImages(ImageResources.INSTANCE.getApplicationImages());
 
         this.config = config;
--- a/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java	Mon Oct 01 19:16:32 2018 +0200
@@ -34,6 +34,7 @@
 import net.sourceforge.jnlp.runtime.Translator;
 import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.util.ScreenFinder;
+import net.sourceforge.swing.SwingUtils;
 
 /**
  * This class will provide a visual way of viewing cache.
@@ -55,6 +56,8 @@
      */
     public CacheViewer(DeploymentConfiguration config) {
         super((Frame) null, dialogTitle, true); // Don't need a parent.
+        this.setName("CacheViewer");
+        SwingUtils.info(this);
         this.config = config;
         if (config == null) {
             throw new IllegalArgumentException("config: " + config);
--- a/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java	Mon Oct 01 19:16:32 2018 +0200
@@ -45,7 +45,6 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.WindowConstants;
 import javax.swing.border.EmptyBorder;
@@ -59,6 +58,7 @@
 import net.sourceforge.jnlp.security.viewer.CertificatePane;
 import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.util.logging.OutputController;
+import net.sourceforge.swing.SwingUtils;
 
 /**
  * This is the control panel for Java. It provides a GUI for modifying the
@@ -418,8 +418,7 @@
             // ignore; not a big deal
         }
 
-
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
             @Override
             public void run() {
                 final ControlPanel editor = new ControlPanel(config);
--- a/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java	Mon Oct 01 19:16:32 2018 +0200
@@ -30,6 +30,7 @@
 import net.sourceforge.jnlp.*;
 import net.sourceforge.jnlp.splashscreen.SplashController;
 import net.sourceforge.jnlp.util.*;
+import net.sourceforge.swing.SwingUtils;
 
 /**
  * The applet environment including stub, context, and frame.  The
@@ -188,7 +189,7 @@
             }
 
             try {
-                SwingUtilities.invokeAndWait(new Runnable() {
+                SwingUtils.callOnAppContext(new Runnable() {
                     @Override
                     public void run() {
                         // do first because some applets need to be displayed before
--- a/netx/net/sourceforge/jnlp/runtime/Boot.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/Boot.java	Mon Oct 01 19:16:32 2018 +0200
@@ -47,6 +47,7 @@
 
 import static net.sourceforge.jnlp.runtime.Translator.R;
 import net.sourceforge.jnlp.runtime.html.browser.LinkingBrowser;
+import net.sourceforge.swing.SwingUtils;
 
 /**
  * This is the main entry point for the JNLP client. The main method parses the
@@ -112,11 +113,16 @@
 
         if (optionParser.hasOption(OptionsDefinitions.OPTIONS.VIEWER)) {
             try {
-                CertificateViewer.main(null);
-                JNLPRuntime.exit(0);
+                SwingUtils.invokeAndWait(new Runnable() {
+                    @Override
+                    public void run() {
+                        CertificateViewer.showCertificateViewer();
+                    }
+                });
             } catch (Exception e) {
                 OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e);
             }
+            JNLPRuntime.exit(0);
         }
 
         if (optionParser.hasOption(OptionsDefinitions.OPTIONS.VERSION)) {
--- a/netx/net/sourceforge/jnlp/runtime/HtmlBoot.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/HtmlBoot.java	Mon Oct 01 19:16:32 2018 +0200
@@ -45,7 +45,6 @@
 import java.util.List;
 import java.util.Map;
 import javax.swing.JFrame;
-import javax.swing.SwingUtilities;
 import net.sourceforge.jnlp.JNLPSplashScreen;
 import net.sourceforge.jnlp.OptionsDefinitions;
 import net.sourceforge.jnlp.ParserSettings;
@@ -58,6 +57,7 @@
 
 import static net.sourceforge.jnlp.runtime.Translator.R;
 import net.sourceforge.jnlp.util.optionparser.OptionParser;
+import net.sourceforge.swing.SwingUtils;
 
 public final class HtmlBoot {
 
@@ -111,7 +111,7 @@
 
     boolean run(Map<String, List<String>> extra) {
         if (!optionParser.hasOption(OptionsDefinitions.OPTIONS.HEADLESS)) {
-            SwingUtilities.invokeLater(new Runnable() {
+            SwingUtils.invokeLater(new Runnable() {
 
                 @Override
                 public void run() {
@@ -157,7 +157,7 @@
                 //close all applets in time
                 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                 //f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-                SwingUtilities.invokeLater(new Runnable() {
+                SwingUtils.invokeLater(new Runnable() {
                     @Override
                     public void run() {
                         Point movement = changeMovementSigns(move);
@@ -180,7 +180,7 @@
         } catch (final Exception ex) {
             OutputController.getLogger().log(ex);
             if (splashScreen != null) {
-                SwingUtilities.invokeLater(new Runnable() {
+                SwingUtils.invokeLater(new Runnable() {
 
                     @Override
                     public void run() {
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Mon Oct 01 19:16:32 2018 +0200
@@ -20,7 +20,6 @@
 
 import java.awt.EventQueue;
 import java.awt.GraphicsEnvironment;
-import static java.awt.GraphicsEnvironment.isHeadless;
 import java.awt.HeadlessException;
 import java.io.File;
 import java.io.FileInputStream;
@@ -51,7 +50,6 @@
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import javax.swing.JOptionPane;
-import javax.swing.JWindow;
 import javax.swing.UIManager;
 import javax.swing.text.html.parser.ParserDelegator;
 
--- a/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java	Mon Oct 01 19:16:32 2018 +0200
@@ -23,12 +23,12 @@
 import java.security.AccessControlException;
 import java.security.Permission;
 
-import javax.swing.JWindow;
 
 import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
 import net.sourceforge.jnlp.services.ServiceUtil;
 import net.sourceforge.jnlp.util.logging.OutputController;
 import net.sourceforge.jnlp.util.WeakList;
+import net.sourceforge.swing.SwingUtils;
 import sun.awt.AWTSecurityManager;
 import sun.awt.AppContext;
 
@@ -114,7 +114,8 @@
         // called for it (and not disposed).
 
         if (!JNLPRuntime.isHeadless()) {
-            new JWindow().getOwner();
+            /* is it really useful ? */
+            SwingUtils.getOrCreateWindowOwner();
         }
 
         mainAppContext = AppContext.getAppContext();
--- a/netx/net/sourceforge/jnlp/security/SecurityDialog.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialog.java	Mon Oct 01 19:16:32 2018 +0200
@@ -46,6 +46,7 @@
 import java.security.cert.X509Certificate;
 
 import javax.swing.JDialog;
+import net.sourceforge.swing.SwingUtils;
 
 import net.sourceforge.jnlp.JNLPFile;
 import net.sourceforge.jnlp.runtime.JNLPClassLoader.SecurityDelegate;
@@ -65,7 +66,6 @@
 import net.sourceforge.jnlp.security.dialogs.SingleCertInfoPane;
 import net.sourceforge.jnlp.security.dialogs.ViwableDialog;
 import net.sourceforge.jnlp.security.dialogs.apptrustwarningpanel.AppTrustWarningDialog;
-import net.sourceforge.jnlp.util.ScreenFinder;
 import net.sourceforge.jnlp.util.logging.OutputController;
 
 /**
@@ -227,12 +227,20 @@
     private void initDialog() {
         String dialogTitle = createTitle();
 
+        // Note: ViwableDialog methods are defered until show():
         getViwableDialog().setTitle(dialogTitle);
         getViwableDialog().setModalityType(ModalityType.MODELESS);
 
         getViwableDialog().setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 
-        installPanel();
+        // Initialize panel now as its constructor may call getViwableDialog() defered methods
+        // to modify dialog state:  
+        SwingUtils.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                installPanel();
+            }
+        });
 
         getViwableDialog().pack();
         getViwableDialog().centerDialog();
@@ -251,11 +259,14 @@
 
             @Override
             public void windowOpened(WindowEvent e) {
-                if (e.getSource() instanceof SecurityDialog) {
-                    SecurityDialog dialog = (SecurityDialog) e.getSource();
-                    dialog.getViwableDialog().setResizable(true);
-                    dialog.setValue(null);
-                }
+                getViwableDialog().setResizable(true);
+                SecurityDialog.this.setValue(null);
+            }
+            @Override
+            public void windowClosed(WindowEvent e) {
+                // called if the user closes the window directly (dispose on close)
+                // always dispose() to unlock message processing
+                getViwableDialog().dispose();
             }
         };
         getViwableDialog().addWindowListener(adapter);
--- a/netx/net/sourceforge/jnlp/security/SecurityDialogs.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/security/SecurityDialogs.java	Mon Oct 01 19:16:32 2018 +0200
@@ -47,7 +47,7 @@
 import java.util.concurrent.Semaphore;
 
 import javax.swing.JDialog;
-import javax.swing.SwingUtilities;
+import net.sourceforge.swing.SwingUtils;
 
 import net.sourceforge.jnlp.JNLPFile;
 import net.sourceforge.jnlp.cache.Resource;
@@ -320,7 +320,7 @@
         /*
          * If this is the event dispatch thread the use the hack
          */
-        if (SwingUtilities.isEventDispatchThread()) {
+        if (SwingUtils.isEventDispatchThread()) {
             /*
              * Create a tiny modal dialog (which creates a new EventQueue for
              * this AppContext, but blocks the original client EventQueue) and
@@ -329,6 +329,8 @@
              * continue processing
              */
             final JDialog fakeDialog = new JDialog();
+            fakeDialog.setName("FakeDialog");
+            SwingUtils.info(fakeDialog);
             fakeDialog.setSize(0, 0);
             fakeDialog.setResizable(false);
             fakeDialog.setModalityType(ModalityType.APPLICATION_MODAL);
--- a/netx/net/sourceforge/jnlp/security/dialogs/ViwableDialog.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/security/dialogs/ViwableDialog.java	Mon Oct 01 19:16:32 2018 +0200
@@ -45,6 +45,7 @@
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 import javax.swing.JDialog;
+import net.sourceforge.swing.SwingUtils;
 import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.util.ScreenFinder;
 
@@ -57,18 +58,23 @@
  */
 public class ViwableDialog {
 
-    private JDialog jd;
+    private JDialog jd = null;
     List<Runnable> operations = new ArrayList<Runnable>();
 
     public ViwableDialog() {
     }
 
-    private JDialog crateJDialog() {
+    private JDialog createJDialog() {
         jd = new JDialog();
+        jd.setName("ViwableDialog");
+        SwingUtils.info(jd);
         jd.setIconImages(ImageResources.INSTANCE.getApplicationImages());
+        
         for (Runnable operation : operations) {
             operation.run();
         }
+        // prune operations. May throw NPE if operations used after createJDialog()
+        operations = null;
         return jd;
     }
 
@@ -100,10 +106,15 @@
     }
 
     public void show() {
-        if (jd == null) {
-            jd = crateJDialog();
-        }
-        jd.setVisible(true);
+        SwingUtils.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if (jd == null) {
+                    jd = createJDialog();
+                }
+                jd.setVisible(true);
+            }
+        });
     }
 
     /**
@@ -111,9 +122,13 @@
      * choice (Ok, Cancel, etc) or closed the window
      */
     public void dispose() {
-        notifySelectionMade();
+        // avoid reentrance:
         if (jd != null) {
+            notifySelectionMade();
+
             jd.dispose();
+            // recycle:
+            jd = null;
         }
     }
 
@@ -190,12 +205,10 @@
     }
 
     public void setResizable(final boolean b) {
-        operations.add(new Runnable() {
-            @Override
-            public void run() {
-                jd.setResizable(b);
-            }
-        });
+        // not defered: called when alive
+        if (jd != null) {
+            jd.setResizable(b);
+        }
     }
 
     public void addWindowListener(final WindowAdapter adapter) {
--- a/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java	Mon Oct 01 19:16:32 2018 +0200
@@ -41,18 +41,16 @@
 
 import java.awt.BorderLayout;
 import java.awt.Container;
-import java.awt.Dimension;
 import java.awt.Frame;
-import java.awt.Toolkit;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 
 import javax.swing.JDialog;
-import javax.swing.UIManager;
 
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.util.ScreenFinder;
+import net.sourceforge.swing.SwingUtils;
 
 public class CertificateViewer extends JDialog {
 
@@ -63,6 +61,8 @@
 
     public CertificateViewer() {
         super((Frame) null, dialogTitle, true);
+        this.setName("CertificateViewer");
+        SwingUtils.info(this);
         setIconImages(ImageResources.INSTANCE.getApplicationImages());
 
         Container contentPane = getContentPane();
@@ -98,7 +98,7 @@
         ScreenFinder.centerWindowsToCurrentScreen(this);
     }
 
-    public static void showCertificateViewer() throws Exception {
+    public static void showCertificateViewer() {
         JNLPRuntime.initialize(true);
 
         CertificateViewer cv = new CertificateViewer();
@@ -109,6 +109,11 @@
     }
 
     public static void main(String[] args) throws Exception {
-        CertificateViewer.showCertificateViewer();
+        SwingUtils.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                CertificateViewer.showCertificateViewer();
+            }
+        });
     }
 }
--- a/netx/net/sourceforge/jnlp/splashscreen/impls/defaultsplashscreen2012/BasePainter.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/splashscreen/impls/defaultsplashscreen2012/BasePainter.java	Mon Oct 01 19:16:32 2018 +0200
@@ -55,7 +55,7 @@
 import java.util.Observable;
 import java.util.Observer;
 
-import javax.swing.SwingUtilities;
+import net.sourceforge.swing.SwingUtils;
 import net.sourceforge.jnlp.runtime.Translator;
 import net.sourceforge.jnlp.splashscreen.SplashUtils.SplashReason;
 import net.sourceforge.jnlp.splashscreen.parts.BasicComponentSplashScreen;
@@ -558,18 +558,16 @@
 
     @Override
     public void update(Observable o, Object arg) {
-        try {
-            SwingUtilities.invokeAndWait(new Runnable() {
+        SwingUtils.invokeAndWait(new Runnable() {
 
-                @Override
-                public void run() {
+            @Override
+            public void run() {
+                if (master.isAnimationRunning()) {
                     ExtensionManager.getExtension().animate();
                     master.repaint();
                 }
-            });
-        } catch (Exception ex) {
-            OutputController.getLogger().log(ex);
-        }
+            }
+        });
     }
 
     public BasicComponentSplashScreen getMaster() {
--- a/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java	Mon Oct 01 19:16:32 2018 +0200
@@ -57,7 +57,7 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
-import javax.swing.SwingUtilities;
+import net.sourceforge.swing.SwingUtils;
 import net.sourceforge.jnlp.controlpanel.CachePane;
 import net.sourceforge.jnlp.util.logging.JavaConsole;
 
@@ -81,6 +81,8 @@
 
         JOptionPane optionPane = new JOptionPane(mainPanel, JOptionPane.ERROR_MESSAGE);
         final JDialog errorDialog = optionPane.createDialog(R("Error"));
+        errorDialog.setName("BasicExceptionDialog");
+        SwingUtils.info(errorDialog);
         errorDialog.setIconImages(ImageResources.INSTANCE.getApplicationImages());
 
         final JPanel quickInfoPanelAll = new JPanel();
@@ -179,7 +181,7 @@
 
             @Override
             public void actionPerformed(java.awt.event.ActionEvent evt) {
-                SwingUtilities.invokeLater(new Runnable() {
+                SwingUtils.invokeLater(new Runnable() {
 
                     @Override
                     public void run() {
--- a/netx/net/sourceforge/jnlp/util/FileUtils.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/util/FileUtils.java	Mon Oct 01 19:16:32 2018 +0200
@@ -34,7 +34,11 @@
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.nio.file.Files;
-import java.nio.file.attribute.*;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclEntryFlag;
+import java.nio.file.attribute.AclEntryPermission;
+import java.nio.file.attribute.AclEntryType;
+import java.nio.file.attribute.AclFileAttributeView;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -42,7 +46,7 @@
 
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
+import net.sourceforge.swing.SwingUtils;
 
 import net.sourceforge.jnlp.config.DirectoryValidator;
 import net.sourceforge.jnlp.config.DirectoryValidator.DirectoryCheckResults;
@@ -374,7 +378,7 @@
      * @param frame a {@link JFrame} to act as parent to this dialog
      */
     public static void showReadOnlyDialog(final Component frame) {
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
             @Override
             public void run() {
                 JOptionPane.showMessageDialog(frame, R("RFileReadOnly"), R("Warning"), JOptionPane.WARNING_MESSAGE);
@@ -422,7 +426,7 @@
      * @param message a {@link String} giving the specific reason the file could not be opened
      */
     public static void showCouldNotOpenDialog(final Component frame, final String message) {
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
             @Override
             public void run() {
                 JOptionPane.showMessageDialog(frame, message, R("Error"), JOptionPane.ERROR_MESSAGE);
--- a/netx/net/sourceforge/jnlp/util/logging/JavaConsole.java	Mon Oct 01 19:08:34 2018 +0200
+++ b/netx/net/sourceforge/jnlp/util/logging/JavaConsole.java	Mon Oct 01 19:16:32 2018 +0200
@@ -69,10 +69,10 @@
 import javax.swing.JSpinner;
 import javax.swing.JSplitPane;
 import javax.swing.SpinnerNumberModel;
-import javax.swing.SwingUtilities;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.text.DefaultFormatter;
+import net.sourceforge.swing.SwingUtils;
 import net.sourceforge.jnlp.config.DeploymentConfiguration;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 import net.sourceforge.jnlp.util.ImageResources;
@@ -204,6 +204,9 @@
 
     private void initializeWindow(Dimension size, JPanel content) {
         consoleWindow = new JDialog((JFrame) null, R("DPJavaConsole"));
+        consoleWindow.setName("JavaConsole");
+        SwingUtils.info(consoleWindow);
+        
         consoleWindow.addWindowListener(new WindowAdapter() {
 
             @Override
@@ -353,7 +356,7 @@
 
             @Override
             public void actionPerformed(ActionEvent e) {
-                SwingUtilities.invokeLater(new Runnable() {
+                SwingUtils.invokeLater(new Runnable() {
 
                     @Override
                     public void run() {
@@ -407,7 +410,7 @@
     }
 
     public void showConsoleLater(final boolean modal) {
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
 
             @Override
             public void run() {
@@ -417,7 +420,7 @@
     }
 
     public void hideConsoleLater() {
-        SwingUtilities.invokeLater(new Runnable() {
+        SwingUtils.invokeLater(new Runnable() {
 
             @Override
             public void run() {
@@ -512,9 +515,21 @@
         updateModel(null);
     }
 
-    private synchronized void updateModel(Boolean force) {
+    private synchronized void updateModel(final Boolean force) {
         observable.setChanged();
-        observable.notifyObservers(force);
+        
+        SwingUtils.invokeLater(new Runnable() {
+
+            @Override
+            public void run() {
+                // avoid too much processing if already processed:
+                synchronized(observable) {
+                    if (observable.hasChanged() || (Boolean.TRUE.equals(force))) {
+                        observable.notifyObservers(force);
+                    }
+                }
+            }
+        });
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/swing/SwingUtils.java	Mon Oct 01 19:16:32 2018 +0200
@@ -0,0 +1,223 @@
+/* SwingUtils.java
+   Copyright (C) 2018 Red Hat, Inc.
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+package net.sourceforge.swing;
+
+import java.awt.Window;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.swing.JDialog;
+import javax.swing.JWindow;
+import javax.swing.SwingUtilities;
+import net.sourceforge.jnlp.runtime.Translator;
+import net.sourceforge.jnlp.util.logging.OutputController;
+
+/**
+ * Swing / AWT utility class
+ */
+public final class SwingUtils {
+
+    // debugging flags:
+    private static final boolean INFO_DIALOG = false;
+    private static final boolean TRACE_INVOKE_EDT = false;
+    private static final boolean TRACE_TG = false;
+
+    /** main thread group (initialized at startup) */
+    static final ThreadGroup MAIN_GROUP = Thread.currentThread().getThreadGroup();
+
+    private SwingUtils() {
+        // forbidden
+    }
+
+    static void trace(final String msg) {
+        // Use System.err directly for debuging EDT without any conflict with console / logging system
+        System.err.println(msg);
+    }
+
+    static void traceWithStack(final String msg) {
+        trace(msg);
+        new Throwable().printStackTrace();
+    }
+
+    public static void info(final JDialog dialog) {
+        if (INFO_DIALOG) {
+            trace("Dialog[" + dialog.getName() + "]"
+                    + " in TG [" + Thread.currentThread().getThreadGroup() + "]");
+            checkEDT();
+        }
+    }
+
+    public static void checkEDT() {
+        if (!isEventDispatchThread()) {
+            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, new Exception("EDT violation"));
+        }
+    }
+
+    // --- SwingUtilities wrapper ---
+    public static boolean isEventDispatchThread() {
+        return SwingUtilities.isEventDispatchThread();
+    }
+
+    public static void invokeLater(final Runnable doRun) {
+        if (isMainThreadGroup()) {
+            if (isEventDispatchThread()) {
+                if (TRACE_INVOKE_EDT) {
+                    traceWithStack("invokeLater() from EDT: MAY be fixed ?");
+                }
+            }
+            SwingUtilities.invokeLater(doRun);
+        } else {
+            EDT_DAEMON_THREAD_POOL.submit(new Runnable() {
+                @Override
+                public void run() {
+                    SwingUtilities.invokeLater(doRun);
+                }
+            });
+        }
+    }
+
+    public static void callOnAppContext(final Runnable doRun) throws InterruptedException, InvocationTargetException {
+        SwingUtilities.invokeAndWait(doRun);
+    }
+
+    public static void invokeAndWait(final Runnable doRun) {
+        if (isMainThreadGroup()) {
+            if (isEventDispatchThread()) {
+                if (TRACE_INVOKE_EDT) {
+                    traceWithStack("invokeAndWait() from EDT: MAY be fixed ?");
+                }
+                doRun.run();
+            } else {
+                try {
+                    callOnAppContext(doRun);
+                } catch (InterruptedException ie) {
+                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ie);
+                } catch (InvocationTargetException ite) {
+                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ite);
+                }
+            }
+        } else {
+            final Future<?> future = EDT_DAEMON_THREAD_POOL.submit(new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    callOnAppContext(doRun);
+                    return null;
+                }
+            });
+            try {
+                // Wait on Future:
+                future.get();
+            } catch (InterruptedException ie) {
+                OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ie);
+            } catch (ExecutionException ee) {
+                if (ee.getCause() != null) {
+                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ee.getCause());
+                } else {
+                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, ee);
+                }
+            }
+        }
+    }
+
+    private static boolean isMainThreadGroup() {
+        final Thread t = Thread.currentThread();
+        final ThreadGroup g = t.getThreadGroup();
+
+        if (g != MAIN_GROUP) {
+            if (TRACE_TG) {
+                traceWithStack("----------\ncheckThreadGroup: " + t);
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private static final class MainAppContextDaemonThreadFactory implements ThreadFactory {
+
+        private final AtomicInteger threadNumber = new AtomicInteger(1);
+        private final String namePrefix = "itw-edt-thread-";
+
+        @Override
+        public Thread newThread(Runnable r) {
+            final Thread t = new Thread(MAIN_GROUP, r,
+                    namePrefix + threadNumber.getAndIncrement()
+            );
+            if (!t.isDaemon()) {
+                t.setDaemon(true);
+            }
+            if (t.getPriority() != Thread.NORM_PRIORITY) {
+                t.setPriority(Thread.NORM_PRIORITY);
+            }
+            return t;
+        }
+    }
+
+    /** single thread pool with max 1 live daemon thread */
+    private static final ExecutorService EDT_DAEMON_THREAD_POOL = new ThreadPoolExecutor(0, 1,
+            60L, TimeUnit.SECONDS,
+            new LinkedBlockingQueue<Runnable>(),
+            new MainAppContextDaemonThreadFactory()
+    );
+
+    /* shared Window owner */
+    private static Window window = null;
+
+    public static synchronized Window getOrCreateWindowOwner() {
+        if (window == null) {
+            invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        window = new JWindow().getOwner();
+                        window.setName("getOrCreateWindowOwner");
+                    } catch (Exception ex) {
+                        OutputController.getLogger().log(ex);
+                        OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, Translator.R("HEADLESS_MISSCONFIGURED"));
+                    }
+                }
+            });
+        }
+        return window;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/swing/ThreadCheckingRepaintManager.java	Mon Oct 01 19:16:32 2018 +0200
@@ -0,0 +1,120 @@
+/**
+ * License unknown.
+ * based on  Alexander Potochkin's "Debugging Swing, the final summary"
+ * when oracle acquired sun, this blog post was removed, and lives only in copies.
+ * most complex was found:
+http://web.archive.org/web/20150523152453/https://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
+ */
+package net.sourceforge.swing;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import javax.swing.JComponent;
+import javax.swing.RepaintManager;
+import static net.sourceforge.swing.SwingUtils.trace;
+
+/**
+ * For usage of this class, please refer to http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html
+ * <p> To use it, call RepaintManager.setCurrentManager(new ThreadCheckingRepaintManager()) then watch the print out
+ * from the console of all threading violations. </p>
+ */
+public final class ThreadCheckingRepaintManager extends RepaintManager {
+
+    // it is recommended to pass the complete check
+    private boolean completeCheck = true;
+    private boolean checkIsShowing = false;
+
+    /**
+     * Creates ThreadCheckingRepaintManager. You can create one and set it using RepaintManager.setCurrentManager(new
+     * ThreadCheckingRepaintManager()).
+     */
+    public ThreadCheckingRepaintManager() {
+        super();
+    }
+
+    /**
+     * Creates ThreadCheckingRepaintManager. You can create one and set it using RepaintManager.setCurrentManager(new
+     * ThreadCheckingRepaintManager()).
+     *
+     * @param checkIsShowing true to only check showing components.
+     */
+    public ThreadCheckingRepaintManager(boolean checkIsShowing) {
+        super();
+        this.checkIsShowing = checkIsShowing;
+    }
+
+    /**
+     * Initially there was a rule that it is safe to create and use Swing components until they are realized but this
+     * rule is not valid any more, and now it is recommended to interact with Swing from EDT only.
+     * <p/>
+     * That's why completeCheck flag is used - if you test the old program switch it to false, but new applications
+     * should be tested with completeCheck set to true*
+     *
+     * @return true or false. By default, it is false.
+     */
+    public boolean isCompleteCheck() {
+        return completeCheck;
+    }
+
+    /**
+     * @param completeCheck true or false.
+     *
+     * @see #isCompleteCheck()
+     */
+    public void setCompleteCheck(boolean completeCheck) {
+        this.completeCheck = completeCheck;
+    }
+
+    @Override
+    public synchronized void addInvalidComponent(JComponent jComponent) {
+        checkThreadViolations(jComponent);
+        super.addInvalidComponent(jComponent);
+    }
+
+    @Override
+    public synchronized void addDirtyRegion(JComponent jComponent, int i, int i1, int i2, int i3) {
+        checkThreadViolations(jComponent);
+        super.addDirtyRegion(jComponent, i, i1, i2, i3);
+    }
+
+    private void checkThreadViolations(JComponent c) {
+        if (!SwingUtils.isEventDispatchThread() && (completeCheck || checkIsShowing(c))) {
+            Exception exception = new Exception();
+            boolean repaint = false;
+            boolean fromSwing = false;
+            StackTraceElement[] stackTrace = exception.getStackTrace();
+            for (StackTraceElement st : stackTrace) {
+                if (repaint && st.getClassName().startsWith("javax.swing.")) {
+                    fromSwing = true;
+                }
+                if ("repaint".equals(st.getMethodName())) {
+                    repaint = true;
+                }
+            }
+            if (repaint && !fromSwing) {
+                //no problems here, since repaint() is thread safe
+                return;
+            }
+            trace("----------Wrong Thread START");
+            trace(getStrackTraceAsString(exception));
+            trace("----------Wrong Thread END");
+        }
+    }
+
+    @SuppressWarnings({"SimplifiableIfStatement"})
+    private boolean checkIsShowing(JComponent c) {
+        if (this.checkIsShowing) {
+            return c.isShowing();
+        } else {
+            return true;
+        }
+    }
+
+    private String getStrackTraceAsString(Exception e) {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        PrintStream printStream = new PrintStream(byteArrayOutputStream);
+        e.printStackTrace(printStream);
+        printStream.flush();
+        return byteArrayOutputStream.toString();
+    }
+}