changeset 549:b76eaadf30cc

Splashscreen integrated to javaws and plugin
author Jiri Vanek <jvanek@redhat.com>
date Fri, 02 Nov 2012 12:22:09 +0100
parents 34a7d51b30f5
children 6361c91b77ca
files ChangeLog Makefile.am NEWS launcher/javaws.in netx/javaws_splash.png netx/net/sourceforge/jnlp/GuiLaunchHandler.java netx/net/sourceforge/jnlp/JNLPSplashScreen.java netx/net/sourceforge/jnlp/Launcher.java netx/net/sourceforge/jnlp/NetxPanel.java plugin/icedteanp/java/sun/applet/PluginAppletViewer.java tests/reproducers/simple/CountingApplet1/resources/ParallelAppletsTest_1_x_2.html tests/reproducers/simple/simpletest1/resources/netxPlugin.png
diffstat 12 files changed, 417 insertions(+), 101 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Oct 31 17:07:58 2012 +0100
+++ b/ChangeLog	Fri Nov 02 12:22:09 2012 +0100
@@ -1,3 +1,40 @@
+2012-11-02  Jiri Vanek <jvanek@redhat.com>
+
+	Splashscreen integrated to javaws and plugin
+	*  Makefile.am: (edit_launcher_script) added JAVAWS_SPLASH_LOCATION 
+	substitution for installed javaws_splash.png.
+	(install-exec-loca) added installation of javaws_splash.png.
+	* NEWS: mentioned splashscreen
+	* launcher/javaws.in: added SPLASH_LOCATION, as path to image with "java"
+	splash which s then shown until internal vector one appear.
+	* netx/net/sourceforge/jnlp/GuiLaunchHandler.java: splashScreen made volatile,
+	(launchInitialized) splashscreen is created and shown
+	* netx/net/sourceforge/jnlp/JNLPSplashScreen.java: (setSplashImageURL)
+	splash bg image is loaded from given url or default is used if not found
+	or not specified by jnlp/applet. (correctSize) width is calculated from
+	bg image or default is used when no image set. Splash is centered to
+	primary monitor.
+	* netx/net/sourceforge/jnlp/Launcher.java: (launchApplet) and
+	(launchApplication) enriched by handling of splashs.
+	(launchError) overloaded and is now handling forwarding of errors to
+	splash. All relevant calls of launchError enriched by  appletInstance.
+	* netx/net/sourceforge/jnlp/NetxPanel.java: is now implementing
+	SplashController.This is done by setting and wrapping of splashController
+	variable.
+	* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: is now handling 
+	splashscreen for applets in browsers.
+	(framePanel) is now providing panel to be processed (PluginAppletViewer)
+	is now invoking SplashCreator. (replaceSplash) new method which replace 
+	splashscreen with error splashscreen. (removeSplash) new method to remove
+	splash when loading is done. (update) is added to call paint directly
+	(SplashCreator) new internal runnable to create splash
+	* tests/reproducers/simple/CountingApplet1/resources/ParallelAppletsTest_1_x_2.html:
+	second jar made XslowX to track two FIXME introduced in this patch -
+	Launcher's createApplet and PluginAppletViewer's framePanel.
+	* netx/javaws_splash.png: Binary image to be shown before java is launched
+	* tests/reproducers/simple/simpletest1/resources/netxPlugin.png: Binary image
+	to ne used for testing custom splashscreens
+
 2012-10-31 Jana Fabrikova <jfabriko@redhat.com>
 
 	*tests/reproducers/simple/JSToJGet/testcases/JSToJGetTest.java:
--- a/Makefile.am	Wed Oct 31 17:07:58 2012 +0100
+++ b/Makefile.am	Fri Nov 02 12:22:09 2012 +0100
@@ -178,6 +178,7 @@
 edit_launcher_script = sed \
   -e 's|[@]LAUNCHER_BOOTCLASSPATH[@]|$(LAUNCHER_BOOTCLASSPATH)|g' \
   -e 's|[@]JAVAWS_BIN_LOCATION[@]|$(bindir)/$(javaws)|g' \
+  -e 's|[@]JAVAWS_SPLASH_LOCATION[@]|$(datadir)/$(PACKAGE_NAME)/javaws_splash.png|g' \
   -e 's|[@]ITWEB_SETTINGS_BIN_LOCATION[@]|$(bindir)/$(itweb_settings)|g' \
   -e 's|[@]JAVA[@]|$(JAVA)|g' \
   -e 's|[@]JRE[@]|$(SYSTEM_JRE_DIR)|g'
@@ -208,6 +209,7 @@
 	${INSTALL_DATA} $(abs_top_builddir)/liveconnect/lib/classes.jar $(DESTDIR)$(datadir)/$(PACKAGE_NAME)/plugin.jar
 endif
 	${INSTALL_DATA} $(NETX_DIR)/lib/classes.jar $(DESTDIR)$(datadir)/$(PACKAGE_NAME)/netx.jar
+	${INSTALL_DATA} $(NETX_SRCDIR)/javaws_splash.png $(DESTDIR)$(datadir)/$(PACKAGE_NAME)/javaws_splash.png
 	${INSTALL_PROGRAM} launcher.build/$(javaws) $(DESTDIR)$(bindir)
 	${INSTALL_DATA} extra-lib/about.jar $(DESTDIR)$(datadir)/$(PACKAGE_NAME)/about.jar
 	${INSTALL_PROGRAM} launcher.build/$(itweb_settings) $(DESTDIR)$(bindir)
--- a/NEWS	Wed Oct 31 17:07:58 2012 +0100
+++ b/NEWS	Fri Nov 02 12:22:09 2012 +0100
@@ -9,6 +9,7 @@
 CVE-XXXX-YYYY: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=XXXX-YYYY
 
 New in release 1.4 (2012-XX-XX):
+* Splash screen for javaws and plugin
 * Security updates
   - CVE-2012-3422, RH840592: Potential read from an uninitialized memory location
   - CVE-2012-3423, RH841345: Incorrect handling of not 0-terminated strings
--- a/launcher/javaws.in	Wed Oct 31 17:07:58 2012 +0100
+++ b/launcher/javaws.in	Fri Nov 02 12:22:09 2012 +0100
@@ -5,6 +5,7 @@
 LAUNCHER_FLAGS=-Xms8m
 CLASSNAME=net.sourceforge.jnlp.runtime.Boot
 BINARY_LOCATION=@JAVAWS_BIN_LOCATION@
+SPLASH_LOCATION=@JAVAWS_SPLASH_LOCATION@
 PROGRAM_NAME=javaws
 CP=@JRE@/lib/rt.jar
 
@@ -15,6 +16,10 @@
 i=0
 j=0
 
+SPLASH="false"
+if [ "x$ICEDTEA_WEB_SPLASH" = "x" ] ; then
+SPLASH="true"
+fi;
 while [ "$#" -gt "0" ]; do
   case "$1" in
     -J*)
@@ -24,6 +29,9 @@
     *)
       ARGS[$j]="$1"
       j=$((j+1))
+      if [ "$1" = "-headless" ] ; then
+        SPLASH="false"
+      fi
       ;;
   esac
   shift
@@ -32,6 +40,10 @@
 k=0
 COMMAND[k]="${JAVA}"
 k=$((k+1))
+if [ "$SPLASH" = "true" ] ; then
+COMMAND[k]="-splash:${SPLASH_LOCATION}"
+k=$((k+1))
+fi;
 COMMAND[k]="${LAUNCHER_BOOTCLASSPATH}"
 k=$((k+1))
 COMMAND[k]="${LAUNCHER_FLAGS}"
Binary file netx/javaws_splash.png has changed
--- a/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Wed Oct 31 17:07:58 2012 +0100
+++ b/netx/net/sourceforge/jnlp/GuiLaunchHandler.java	Fri Nov 02 12:22:09 2012 +0100
@@ -1,5 +1,5 @@
 /* GuiLaunchHandler.java
-   Copyright (C) 2011 Red Hat, Inc.
+   Copyright (C) 2012 Red Hat, Inc.
 
 This file is part of IcedTea.
 
@@ -54,7 +54,7 @@
  */
 public class GuiLaunchHandler extends AbstractLaunchHandler {
 
-    private JNLPSplashScreen splashScreen = null;
+    private volatile JNLPSplashScreen splashScreen = null;
     private final Object mutex = new Object();
     private UpdatePolicy policy = UpdatePolicy.ALWAYS;
 
@@ -80,10 +80,11 @@
     }
 
     private void closeSplashScreen() {
-        synchronized(mutex) {
+        synchronized (mutex) {
             if (splashScreen != null) {
                 if (splashScreen.isSplashScreenValid()) {
                     splashScreen.setVisible(false);
+                    splashScreen.stopAnimation();
                 }
                 splashScreen.dispose();
             }
@@ -102,40 +103,56 @@
 
     @Override
     public void launchInitialized(final JNLPFile file) {
-        
+
         int preferredWidth = 500;
         int preferredHeight = 400;
 
         final URL splashImageURL = file.getInformation().getIconLocation(
                 IconDesc.SPLASH, preferredWidth, preferredHeight);
 
+        final ResourceTracker resourceTracker = new ResourceTracker(true);
         if (splashImageURL != null) {
-            final ResourceTracker resourceTracker = new ResourceTracker(true);
             resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, policy);
-            synchronized(mutex) {
-                try {
-                    SwingUtilities.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) {
-                    ite.printStackTrace();
-                }
+        }
+        synchronized (mutex) {
+            try {
+                SwingUtilities.invokeAndWait(new Runnable() {
 
-                splashScreen.setSplashImageURL(splashImageURL);
+                    @Override
+                    public void run() {
+                        splashScreen = new JNLPSplashScreen(resourceTracker, file);
+                    }
+                });
+            } catch (InterruptedException ie) {
+                // Wait till splash screen is created
+                while (splashScreen == null);
+            } catch (InvocationTargetException ite) {
+                ite.printStackTrace();
             }
+            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) {
+                ite.printStackTrace();
+            }
+
+
         }
-        
+
         SwingUtilities.invokeLater(new Runnable() {
+
             @Override
             public void run() {
-                if (splashImageURL != null) {
-                    synchronized(mutex) {
+                if (splashScreen != null) {
+                    synchronized (mutex) {
                         if (splashScreen.isSplashScreenValid()) {
                             splashScreen.setVisible(true);
                         }
--- a/netx/net/sourceforge/jnlp/JNLPSplashScreen.java	Wed Oct 31 17:07:58 2012 +0100
+++ b/netx/net/sourceforge/jnlp/JNLPSplashScreen.java	Fri Nov 02 12:22:09 2012 +0100
@@ -43,19 +43,16 @@
 import java.awt.Graphics2D;
 import java.awt.Image;
 import java.awt.Insets;
-import java.awt.Toolkit;
 import java.io.IOException;
 import java.net.URL;
-
 import javax.imageio.ImageIO;
 import javax.swing.JDialog;
-
 import net.sourceforge.jnlp.cache.ResourceTracker;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
-import net.sourceforge.jnlp.util.ImageResources;
 import net.sourceforge.jnlp.splashscreen.SplashPanel;
 import net.sourceforge.jnlp.splashscreen.SplashUtils;
 import net.sourceforge.jnlp.splashscreen.parts.InformationElement;
+import net.sourceforge.jnlp.util.ImageResources;
 
 public class JNLPSplashScreen extends JDialog {
 
@@ -68,6 +65,7 @@
     public static final  int DEF_WIDTH=635;
     public static final  int DEF_HEIGHT=480;
     private SplashPanel componetSplash;
+    private boolean splashImageLoaded=false;
 
     public JNLPSplashScreen(ResourceTracker resourceTracker, final JNLPFile file) {
 
@@ -78,61 +76,86 @@
         // JNLP file.
 
         this.resourceTracker = resourceTracker;
-
-        this.file=file;    
+        this.file=file;
 
     }
 
     public void setSplashImageURL(URL url) {
-        splashImageUrl = url;
-        splashImage = null;
+        splashImageLoaded = false;
         try {
-            splashImage = ImageIO.read(resourceTracker
-                    .getCacheFile(splashImageUrl));
-            if (splashImage == null) {
-                if (JNLPRuntime.isDebug()) {
-                    System.err.println("Error loading splash image: " + url);
+            if (url != null) {
+                splashImageUrl = url;
+                splashImage = null;
+                try {
+                    splashImage = ImageIO.read(resourceTracker.getCacheFile(splashImageUrl));
+                    if (splashImage == null) {
+                        if (JNLPRuntime.isDebug()) {
+                            System.err.println("Error loading splash image: " + url);
+                        }
+                    }
+                } catch (IOException e) {
+                    if (JNLPRuntime.isDebug()) {
+                        System.err.println("Error loading splash image: " + url);
+                    }
+                    splashImage = null;
+                } catch (IllegalArgumentException argumentException) {
+                    if (JNLPRuntime.isDebug()) {
+                        System.err.println("Error loading splash image: " + url);
+                    }
+                    splashImage = null;
                 }
-                return;
             }
-        } catch (IOException e) {
-            if (JNLPRuntime.isDebug()) {
-                System.err.println("Error loading splash image: " + url);
+
+            if (splashImage == null) {
+                this.setLayout(new BorderLayout());
+                SplashPanel splash = SplashUtils.getSplashScreen(DEF_WIDTH, DEF_HEIGHT);
+                if (splash != null) {
+                    splash.startAnimation();
+                    splash.setInformationElement(InformationElement.createFromJNLP(file));
+                    this.add(splash.getSplashComponent());
+                    this.componetSplash = splash;
+                }
             }
-            splashImage = null;
-            return;
-        } catch (IllegalArgumentException argumentException) {
-            if (JNLPRuntime.isDebug()) {
-                System.err.println("Error loading splash image: " + url);
-            }
-            splashImage = null;
-            return;
+            correctSize();
+        } finally {
+            splashImageLoaded = true;
         }
-
-        correctSize();
     }
 
+    public boolean isSplashImageLoaded() {
+        return splashImageLoaded;
+    }
+
+
     public boolean isSplashScreenValid() {
-        return (splashImage != null);
+        return (splashImage != null) || (componetSplash != null);
     }
 
     private void correctSize() {
-
-        Insets insets = getInsets();
-        int minimumWidth = splashImage.getWidth(null) + insets.left
-                + insets.right;
-        int minimumHeight = splashImage.getHeight(null) + insets.top
-                + insets.bottom;
-        setMinimumSize(new Dimension(minimumWidth, minimumHeight));
-
-        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-        setLocation((screenSize.width - minimumWidth) / 2,
-                (screenSize.height - minimumHeight) / 2);
+        int minimumWidth = DEF_WIDTH;
+        int minimumHeight = DEF_HEIGHT;
+        if (splashImage != null) {
+            Insets insets = getInsets();
+            minimumWidth = splashImage.getWidth(null) + insets.left
+                    + insets.right;
+            minimumHeight = splashImage.getHeight(null) + insets.top
+                    + insets.bottom;
+        }
+        setMinimumSize(new Dimension(0, 0));
+        setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
+        setSize(new Dimension(minimumWidth, minimumHeight));
+        setPreferredSize(new Dimension(minimumWidth, minimumHeight));
+        // Centering to middle of Toolkit.getDefaultToolkit().getScreenSize()
+        // centers to the middle of all monitors. Let's center to the middle
+        // of the primary monitor instead.
+        // TODO center on the 'current' monitor to meet user expectation
+        setLocationRelativeTo(null);
     }
 
     @Override
     public void paint(Graphics g) {
         if (splashImage == null) {
+            super.paint(g);
             return;
         }
 
@@ -141,4 +164,12 @@
         g2.drawImage(splashImage, getInsets().left, getInsets().top, null);
 
     }
+
+    public boolean isCustomSplashscreen() {
+       return (componetSplash!=null);
+    }
+
+    public void stopAnimation() {
+        if (isCustomSplashscreen()) componetSplash.stopAnimation();
+    }
 }
--- a/netx/net/sourceforge/jnlp/Launcher.java	Wed Oct 31 17:07:58 2012 +0100
+++ b/netx/net/sourceforge/jnlp/Launcher.java	Fri Nov 02 12:22:09 2012 +0100
@@ -20,6 +20,7 @@
 
 import java.applet.Applet;
 import java.awt.Container;
+import java.awt.SplashScreen;
 import java.io.File;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
@@ -42,6 +43,8 @@
 
 import javax.swing.SwingUtilities;
 import javax.swing.text.html.parser.ParserDelegator;
+import net.sourceforge.jnlp.runtime.AppletEnvironment;
+import net.sourceforge.jnlp.splashscreen.SplashUtils;
 
 import sun.awt.SunToolkit;
 
@@ -543,6 +546,12 @@
             }
 
             if (JNLPRuntime.getForksAllowed() && file.needsNewVM()) {
+                if (!JNLPRuntime.isHeadless()){
+                    SplashScreen sp = SplashScreen.getSplashScreen();
+                    if (sp!=null) {
+                        sp.close();
+                    }
+                }
                 List<String> netxArguments = new LinkedList<String>();
                 netxArguments.add("-Xnofork");
                 netxArguments.addAll(JNLPRuntime.getInitialArguments());
@@ -652,25 +661,42 @@
      * @param enableCodeBase whether to add the codebase URL to the classloader
      */
     protected ApplicationInstance launchApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
-        if (!file.isApplet())
+        if (!file.isApplet()) {
             throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
-
+        }
+      
+        if (JNLPRuntime.getForksAllowed() && file.needsNewVM()) {
+            if (!JNLPRuntime.isHeadless()) {
+                SplashScreen sp = SplashScreen.getSplashScreen();
+                if (sp != null) {
+                    sp.close();
+                }
+            }
+        }
+        if (handler != null) {
+            handler.launchInitialized(file);
+        }
+        
+        AppletInstance applet = null;
         try {
             ServiceUtil.checkExistingSingleInstance(file);
-            AppletInstance applet = createApplet(file, enableCodeBase, cont);
+            applet = createApplet(file, enableCodeBase, cont);
             applet.initialize();
-
             applet.getAppletEnvironment().startApplet(); // this should be a direct call to applet instance
             return applet;
         } catch (InstanceExistsException ieex) {
             if (JNLPRuntime.isDebug()) {
                 System.out.println("Single instance applet is already running.");
             }
-            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")));
+            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")), applet);
         } catch (LaunchException lex) {
-            throw launchError(lex);
+            throw launchError(lex, applet);
         } catch (Exception ex) {
-            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")));
+            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")), applet);
+        }finally{
+            if (handler != null) {
+                handler.launchStarting(applet);
+            }
         }
     }
 
@@ -678,13 +704,13 @@
      * Gets an ApplicationInstance, but does not launch the applet.
      */
     protected ApplicationInstance getApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
-        if (!file.isApplet())
+        if (!file.isApplet()) {
             throw launchError(new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LNotApplet"), R("LNotAppletInfo")));
-
+        }
+        AppletInstance applet = null;
         try {
             ServiceUtil.checkExistingSingleInstance(file);
-
-            AppletInstance applet = createApplet(file, enableCodeBase, cont);
+            applet = createApplet(file, enableCodeBase, cont);
             applet.initialize();
             return applet;
 
@@ -692,11 +718,11 @@
             if (JNLPRuntime.isDebug()) {
                 System.out.println("Single instance applet is already running.");
             }
-            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")));
+            throw launchError(new LaunchException(file, ieex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LSingleInstanceExists")), applet);
         } catch (LaunchException lex) {
-            throw launchError(lex);
+            throw launchError(lex, applet);
         } catch (Exception ex) {
-            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")));
+            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCLaunching"), R("LCouldNotLaunch"), R("LCouldNotLaunchInfo")), applet);
         }
     }
 
@@ -715,8 +741,13 @@
      *
      * @param enableCodeBase whether to add the code base URL to the classloader
      */
-    protected AppletInstance createApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
-        try {
+     //FIXME - when multiple applets are on one page, this method is visited simultaneously
+    //and then appelts creates in little bit strange manner. This issue is visible with
+    //randomly showing/notshowing spalshscreens.
+    //See also PluginAppletViewer.framePanel
+    protected  AppletInstance createApplet(JNLPFile file, boolean enableCodeBase, Container cont) throws LaunchException {
+         AppletInstance appletInstance = null;
+         try {
             JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy);
 
             if (enableCodeBase) {
@@ -730,7 +761,6 @@
             // appletInstance is needed by ServiceManager when looking up 
             // services. This could potentially be done in applet constructor
             // so initialize appletInstance before creating applet.
-            AppletInstance appletInstance;
             if (cont == null)
                 appletInstance = new AppletInstance(file, group, loader, null);
             else
@@ -751,7 +781,7 @@
 
             return appletInstance;
         } catch (Exception ex) {
-            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCInit"), R("LInitApplet"), R("LInitAppletInfo")));
+            throw launchError(new LaunchException(file, ex, R("LSFatal"), R("LCInit"), R("LInitApplet"), R("LInitAppletInfo")), appletInstance);
         }
     }
 
@@ -822,6 +852,13 @@
      * caller.
      */
     private LaunchException launchError(LaunchException ex) {
+        return launchError(ex, null);
+    }
+    
+    private LaunchException launchError(LaunchException ex, AppletInstance applet) {
+        if (applet != null) {
+            SplashUtils.showErrorCaught(ex, applet);
+        }
         if (handler != null)
             handler.launchError(ex);
 
@@ -861,7 +898,7 @@
         new ParserDelegator();
     }
 
-    /**
+       /**
      * This runnable is used to call the appropriate launch method
      * for the application, applet, or installer in its thread group.
      */
--- a/netx/net/sourceforge/jnlp/NetxPanel.java	Wed Oct 31 17:07:58 2012 +0100
+++ b/netx/net/sourceforge/jnlp/NetxPanel.java	Fri Nov 02 12:22:09 2012 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2012 Red Hat, Inc.
  * This file is part of IcedTea, http://icedtea.classpath.org
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -22,7 +22,6 @@
 
 package net.sourceforge.jnlp;
 
-import net.sourceforge.jnlp.AppletLog;
 import net.sourceforge.jnlp.runtime.AppletInstance;
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
 
@@ -32,6 +31,8 @@
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import net.sourceforge.jnlp.splashscreen.SplashController;
+import net.sourceforge.jnlp.splashscreen.SplashPanel;
 
 import sun.applet.AppletViewerPanel;
 import sun.awt.SunToolkit;
@@ -42,10 +43,11 @@
  *
  * @author      Francis Kung <fkung@redhat.com>
  */
-public class NetxPanel extends AppletViewerPanel {
+public class NetxPanel extends AppletViewerPanel implements SplashController {
     private PluginBridge bridge = null;
     private boolean exitOnFailure = true;
     private AppletInstance appInst = null;
+    private SplashController splashController;
     private boolean appletAlive;
     private final String uKey;
 
@@ -232,4 +234,32 @@
             SunToolkit.createNewAppContext();
         }
     }
+
+    
+   
+
+    public void setAppletViewerFrame(SplashController framePanel) {
+        splashController=framePanel;
+    }
+
+    @Override
+    public void removeSplash() {
+        splashController.removeSplash();
+    }
+
+    @Override
+    public void replaceSplash(SplashPanel r) {
+        splashController.replaceSplash(r);
+    }
+
+    @Override
+    public int getSplashWidth() {
+        return splashController.getSplashWidth();
+    }
+
+    @Override
+    public int getSplashHeigth() {
+        return splashController.getSplashHeigth();
+    }
+
 }
--- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Wed Oct 31 17:07:58 2012 +0100
+++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java	Fri Nov 02 12:22:09 2012 +0100
@@ -76,6 +76,7 @@
 import java.awt.event.WindowListener;
 import java.awt.print.PageFormat;
 import java.awt.print.Printable;
+import java.awt.Component;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
@@ -93,10 +94,8 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Vector;
 
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -115,6 +114,11 @@
 import sun.misc.Ref;
 
 import com.sun.jndi.toolkit.url.UrlUtil;
+import java.util.Hashtable;
+import java.util.Vector;
+import net.sourceforge.jnlp.splashscreen.SplashController;
+import net.sourceforge.jnlp.splashscreen.SplashPanel;
+import net.sourceforge.jnlp.splashscreen.SplashUtils;
 
 /**
  * Lets us construct one using unix-style one shot behaviors
@@ -141,11 +145,15 @@
         // isn't the case, the awt eventqueue thread's context classloader
         // won't be set to a JNLPClassLoader, and when an applet class needs
         // to be loaded from the awt eventqueue, it won't be found.
+        final int width = Integer.parseInt(atts.get("width"));
+        final int height = Integer.parseInt(atts.get("height"));
         Thread panelInit = new Thread(panel.getThreadGroup(), new Runnable() {
             @Override public void run() {
                 panel.createNewAppContext();
                 // create the frame.
-                PluginAppletViewer.framePanel(identifier, handle, panel);
+                PluginDebug.debug("X and Y are: " + width + " " + height);
+                panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier,handle, width, height, panel));
+
                 panel.init();
                 // Start the applet
                 initEventQueue(panel);
@@ -185,7 +193,7 @@
         try {
             SwingUtilities.invokeAndWait(new Runnable() {
                 public void run() {
-                    panel.getParent().setSize(Integer.valueOf(atts.get("width")), Integer.valueOf(atts.get("height")));
+                    panel.getParent().setSize(width, height);
                 }
             });
         } catch (InvocationTargetException ite) {
@@ -198,6 +206,8 @@
             ie.printStackTrace();
         }
 
+        panel.removeSplash();
+
         AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc);
         AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader());
 
@@ -271,7 +281,7 @@
 // FIXME: declare JSProxy implementation
 @SuppressWarnings("serial")
 public class PluginAppletViewer extends XEmbeddedFrame
-        implements AppletContext, Printable {
+        implements AppletContext, Printable, SplashController {
 
     /**
      *  Enumerates the current status of an applet
@@ -323,26 +333,36 @@
     private Image bufFrameImg;
     private Graphics bufFrameImgGraphics;
 
+
+    private SplashPanel splashPanel;
+ 
     /**
      * Null constructor to allow instantiation via newInstance()
      */
     public PluginAppletViewer() {
     }
 
-    public static void framePanel(int identifier, long handle, NetxPanel panel) {
+    //FIXME - when multiple applets are on one page, this method is visited simultaneously
+    //and then appelts creates in little bit strange manner. This issue is visible with
+    //randomly showing/notshowing spalshscreens.
+    //See also Launcher.createApplet
+    public static PluginAppletViewer framePanel(int identifier,long handle, int width, int height, NetxPanel panel) {
 
         PluginDebug.debug("Framing ", panel);
-
-        // SecurityManager MUST be set, and only privileged code may call reFrame()
+ 
+        // SecurityManager MUST be set, and only privileged code may call framePanel()
         System.getSecurityManager().checkPermission(new AllPermission());
 
         PluginAppletViewer appletFrame = new PluginAppletViewer(handle, identifier, panel);
-
-        appletFrame.add("Center", panel);
-        appletFrame.pack();
-
+        
         appletFrame.appletEventListener = new AppletEventListener(appletFrame, appletFrame);
         panel.addAppletListener(appletFrame.appletEventListener);
+         // Clear references, if any
+        if (applets.containsKey(identifier)) {
+            PluginAppletViewer oldFrame = applets.get(identifier);            
+            oldFrame.remove(panel);
+            panel.removeAppletListener(oldFrame.appletEventListener);
+        }
 
         appletsLock.lock();
         applets.put(identifier, appletFrame);
@@ -350,6 +370,7 @@
         appletsLock.unlock();
 
         PluginDebug.debug(panel, " framed");
+               return appletFrame;
     }
 
     /**
@@ -383,9 +404,88 @@
         };
 
         addWindowListener(windowEventListener);
+        final AppletPanel fPanel = panel;
+        try {
+            SwingUtilities.invokeAndWait(new SplashCreator(fPanel));
+        } catch (Exception e) {
+            e.printStackTrace(); // Not much we can do other than  print
+        }
 
     }
 
+    public void replaceSplash(final SplashPanel newSplash) {
+        if (splashPanel == null) {
+            return;
+        }
+        if (newSplash == null) {
+            removeSplash();
+            return;
+        }
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+
+                public void run() {
+                    splashPanel.getSplashComponent().setVisible(false);
+                    splashPanel.stopAnimation();
+                    remove(splashPanel.getSplashComponent());
+                    newSplash.setPercentage(splashPanel.getPercentage());
+                    newSplash.setSplashWidth(splashPanel.getSplashWidth());
+                    newSplash.setSplashHeight(splashPanel.getSplashHeight());
+                    newSplash.adjustForSize();
+                    splashPanel = newSplash;
+                    add("Center", splashPanel.getSplashComponent());
+                    pack();
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace(); // Not much we can do other than print
+        }
+    }
+
+    @Override
+    public void removeSplash() {
+        if (splashPanel == null) {
+            return;
+        }
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+
+                public void run() {
+                    splashPanel.getSplashComponent().setVisible(false);
+                    splashPanel.stopAnimation();
+                    remove(splashPanel.getSplashComponent());
+                    splashPanel = null;
+                    remove(panel);
+                    // Re-add the applet to notify container
+                    add(panel);
+                    panel.setVisible(true);
+                    pack();
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace(); // Not much we can do other than print
+        }
+    }
+
+    @Override
+    public int getSplashWidth() {
+        if (splashPanel != null) {
+            return splashPanel.getSplashWidth();
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public int getSplashHeigth() {
+        if (splashPanel != null) {
+            return splashPanel.getSplashHeight();
+        } else {
+            return -1;
+        }
+    }
+   
+
     private static class AppletEventListener implements AppletListener {
         final Frame frame;
         final PluginAppletViewer appletViewer;
@@ -401,7 +501,6 @@
             panelLock.lock();
             panelLive.signalAll();
             panelLock.unlock();
-
             switch (evt.getID()) {
                 case AppletPanel.APPLET_RESIZE: {
                     if (src != null) {
@@ -436,6 +535,23 @@
 
                     break;
                 }
+                case AppletPanel.APPLET_START: {
+                    if (src.status != AppletPanel.APPLET_INIT && src.status != AppletPanel.APPLET_STOP) {
+                        String s="Applet started, but but reached invalid state";
+                        PluginDebug.debug(s);
+                        SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s));
+                        appletViewer.replaceSplash(sp);
+                    }
+
+                    break;
+                }
+                case AppletPanel.APPLET_ERROR: {
+                    String s="Undefined error causing applet not to staart appeared";
+                    PluginDebug.debug(s);
+                        SplashPanel sp=SplashUtils.getErrorSplashScreen(appletViewer.panel.getWidth(), appletViewer.panel.getHeight(), new Exception(s));
+                        appletViewer.replaceSplash(sp);
+                    break;
+                }
             }
         }
     }
@@ -517,6 +633,8 @@
                 waitForAppletInit(applets.get(identifier).panel);
 
                 // Should we proceed with reframing?
+                 PluginDebug.debug("Init complete");
+
                 if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) {
                     destroyApplet(identifier);
                     return;
@@ -656,6 +774,8 @@
      */
     public static void waitForAppletInit(NetxPanel panel) {
 
+        PluginDebug.debug("Waiting for applet init");
+
         // Wait till initialization finishes
         long maxTimeToSleep = APPLET_TIMEOUT;
 
@@ -2103,7 +2223,7 @@
      * the parent class's update() just does a couple of checks (both of
      * which are accounted for) and then calls paint anyway.
      */
-    public void update(Graphics g) {
+    public void paint(Graphics g) {
 
         // If the image or the graphics don't exist, create new ones
         if (bufFrameImg == null || bufFrameImgGraphics == null) {
@@ -2112,12 +2232,20 @@
         }
 
         // Paint off-screen
-        paint(bufFrameImgGraphics);
+        for (Component c: this.getComponents()) {
+                c.paint(bufFrameImgGraphics);
+        }
 
         // Draw the painted image
         g.drawImage(bufFrameImg, 0, 0, this);
     }
-
+    
+    
+    @Override
+    public void update(Graphics g) {
+        paint(g);
+    }
+  
     /**
      * Waits on a given condition queue until timeout.
      *
@@ -2151,4 +2279,25 @@
         // Return the difference
         return System.nanoTime() - sleepStart;
     }
+
+    private class SplashCreator implements Runnable {
+
+        private final AppletPanel fPanel;
+
+        public SplashCreator(AppletPanel fPanel) {
+            this.fPanel = fPanel;
+        }
+
+        public void run() {
+            add("Center", fPanel);
+            fPanel.setVisible(false);
+            splashPanel = SplashUtils.getSplashScreen(fPanel.getWidth(), fPanel.getHeight());
+            if (splashPanel != null) {
+                splashPanel.startAnimation();
+                PluginDebug.debug("Added splash " + splashPanel);
+                add("Center", splashPanel.getSplashComponent());
+            }
+            pack();
+        }
+    }
 }
--- a/tests/reproducers/simple/CountingApplet1/resources/ParallelAppletsTest_1_x_2.html	Wed Oct 31 17:07:58 2012 +0100
+++ b/tests/reproducers/simple/CountingApplet1/resources/ParallelAppletsTest_1_x_2.html	Fri Nov 02 12:22:09 2012 +0100
@@ -36,7 +36,7 @@
 
  -->
 <html><head></head><body bgcolor="blue">
-<p><applet code="CountingApplet1.class" archive="CountingApplet1.jar" codebase="." width="50" height="100">
+<p><applet code="CountingApplet1.class" archive="XslowXCountingApplet1.jar" codebase="." width="50" height="100">
 </applet></p>
 <p><applet code="CountingApplet2.class" archive="CountingApplet2.jar" codebase="." width="100" height="50">
 </applet></p>
Binary file tests/reproducers/simple/simpletest1/resources/netxPlugin.png has changed