In devmode, call plugin.disconnect() on window unload

This change hooks up the plugin.disconnect() call to the window
unload callbacks. (Notice that in both cases this actually hooks
them to an iframe window, not the parent window itself.)

If the plugin doesn't have a disconnect() method (true today)
then it does nothing.

This is a prerequisite for fixing the Firefox memory leak.
For the next step, see:
https://gwt-review.googlesource.com/4680

Change-Id: Iff9f366bc7e34d5d2bb4098a49e0aaa3ca0aeb34
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/devmode.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/devmode.js
index 20b53f2..c6e4c59 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/devmode.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/devmode.js
@@ -174,14 +174,6 @@
 /******************************************************************************
  * Helper functions for the Development Mode startup code. Listed alphabetically
  *****************************************************************************/
-function disconnectPlugin() {
-  try {
-    // wrap in try/catch since plugins are not required to supply this
-    plugin.disconnect();
-  } catch (e) {
-  }
-}
-
 function doBrowserSpecificFixes() {
   var ua = navigator.userAgent.toLowerCase();
   if (ua.indexOf("gecko") != -1) {
@@ -375,7 +367,6 @@
   $moduleBase = moduleBase;
   __gwt_getProperty = computePropValue;
   
-  window.onunload = function() { };
   doBrowserSpecificFixes();
 
   if (!findPluginXPCOM()) {
@@ -391,6 +382,16 @@
   if (plugin == null) {
     loadIframe("http://www.gwtproject.org/missing-plugin/");
   } else {
-    window.onUnload = disconnectPlugin();
+    // take over the onunload function, wrapping any existing call if it exists
+    var oldUnload = window.onunload;
+    window.onunload = function() {
+      // run wrapped unload first in case it is running gwt code
+      !!oldUnload && oldUnload();
+      try {
+        // wrap in try/catch since plugins are not required to supply this
+        plugin.disconnect();
+      } catch (e) {
+      }
+    };
   }
 }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
index 3e545be..81d6943 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
@@ -283,7 +283,11 @@
   } else {
     if (plugin.connect(url, topWin.__gwt_SessionID, $hosted, $moduleName,
         $hostedHtmlVersion)) {
-      window.onUnload = function() {
+      // take over the onunload function, wrapping any existing call if it exists
+      var oldUnload = window.onunload;
+      window.onunload = function() {
+        // run wrapped unload first in case it is running gwt code
+        !!oldUnload && oldUnload();
         try {
           // wrap in try/catch since plugins are not required to supply this
           plugin.disconnect();
@@ -312,9 +316,6 @@
     .replace(/\"/g,""");
 }
 
-window.onunload = function() {
-};
-
 // Lightweight metrics
 window.fireOnModuleLoadStart = function(className) {
   $stats && $stats({moduleName:$moduleName, sessionId:$sessionId, subSystem:'startup', evtGroup:'moduleStartup', millis:(new Date()).getTime(), type:'onModuleLoadStart', className:className});