Mercurial > hg > release > icedtea-web-1.8
changeset 1508:31043cd51d7f
Fixed EDT hanging
line wrap: on
line diff
--- a/AUTHORS Mon Oct 01 19:04:14 2018 +0200 +++ b/AUTHORS Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/ChangeLog Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/GuiLaunchHandler.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/JNLPSplashScreen.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/Launcher.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/about/AboutDialog.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/runtime/Boot.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/runtime/HtmlBoot.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/security/SecurityDialog.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/security/SecurityDialogs.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/security/dialogs/ViwableDialog.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/splashscreen/impls/defaultsplashscreen2012/BasePainter.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java Mon Oct 01 19:16:36 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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/util/FileUtils.java Mon Oct 01 19:16:36 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; @@ -391,7 +395,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); @@ -439,7 +443,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:04:14 2018 +0200 +++ b/netx/net/sourceforge/jnlp/util/logging/JavaConsole.java Mon Oct 01 19:16:36 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:36 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:36 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(); + } +}