--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -136,16 +136,20 @@ var gDevToolsBrowser = exports.gDevTools
break;
case "nsPref:changed":
if (prefName.endsWith("enabled")) {
for (let win of this._trackedBrowserWindows) {
this.updateCommandAvailability(win);
}
}
break;
+ case "domwindowopened":
+ let win = subject.QueryInterface(Ci.nsIDOMEventTarget);
+ win.addEventListener("DOMContentLoaded", this, { once: true });
+ break;
}
},
_prefObserverRegistered: false,
ensurePrefObserver: function () {
if (!this._prefObserverRegistered) {
this._prefObserverRegistered = true;
@@ -397,42 +401,59 @@ var gDevToolsBrowser = exports.gDevTools
* Move WebIDE widget to the navbar
*/
// Used by webide.js
moveWebIDEWidgetInNavbar: function () {
CustomizableUI.addWidgetToArea("webide-button", CustomizableUI.AREA_NAVBAR);
},
/**
+ * Starts setting up devtools on a given browser window. This method is
+ * called on DOMContentLoaded, so earlier than registerBrowserWindow which
+ * is called after delayed-startup notification. This method should only do
+ * what has to be done early. Otherwise devtools should be initialized lazily
+ * to prevent overloading Firefox startup.
+ *
+ * @param {ChromeWindow} window
+ * The window to which devtools should be hooked to.
+ */
+ _onBrowserWindowLoaded: function (win) {
+ // This method is called for all top level window, only consider firefox
+ // windows
+ if (!win.gBrowser || !win.location.href.endsWith("browser.xul")) {
+ return;
+ }
+ BrowserMenus.addMenus(win.document);
+ win.addEventListener("unload", this);
+ },
+
+ /**
* Add this DevTools's presence to a browser window's document
*
- * @param {XULDocument} doc
- * The document to which devtools should be hooked to.
+ * @param {ChromeWindow} win
+ * The window to which devtools should be hooked to.
*/
_registerBrowserWindow: function (win) {
if (gDevToolsBrowser._trackedBrowserWindows.has(win)) {
return;
}
gDevToolsBrowser._trackedBrowserWindows.add(win);
- BrowserMenus.addMenus(win.document);
-
// Register the Developer widget in the Hamburger menu or navbar
// only once menus are registered as it depends on it.
gDevToolsBrowser.installDeveloperWidget();
// Inject lazily DeveloperToolbar on the chrome window
loader.lazyGetter(win, "DeveloperToolbar", function () {
let { DeveloperToolbar } = require("devtools/client/shared/developer-toolbar");
return new DeveloperToolbar(win);
});
this.updateCommandAvailability(win);
this.ensurePrefObserver();
- win.addEventListener("unload", this);
let tabContainer = win.gBrowser.tabContainer;
tabContainer.addEventListener("TabSelect", this, false);
tabContainer.addEventListener("TabOpen", this, false);
tabContainer.addEventListener("TabClose", this, false);
tabContainer.addEventListener("TabPinned", this, false);
tabContainer.addEventListener("TabUnpinned", this, false);
},
@@ -619,23 +640,26 @@ var gDevToolsBrowser = exports.gDevTools
/**
* Called on browser unload to remove menu entries, toolboxes and event
* listeners from the closed browser window.
*
* @param {XULWindow} win
* The window containing the menu entry
*/
_forgetBrowserWindow: function (win) {
+ // _forgetBrowserWindow can only be called once for each window, but
+ // _registerBrowserWindow may not have been called. Instead, only
+ // _onBrowserWindowLoaded was and we only need to revert that.
+ win.removeEventListener("unload", this);
+ BrowserMenus.removeMenus(win.document);
+
if (!gDevToolsBrowser._trackedBrowserWindows.has(win)) {
return;
}
gDevToolsBrowser._trackedBrowserWindows.delete(win);
- win.removeEventListener("unload", this);
-
- BrowserMenus.removeMenus(win.document);
// Destroy toolboxes for closed window
for (let [target, toolbox] of gDevTools._toolboxes) {
if (toolbox.win.top == win) {
toolbox.destroy();
}
}
@@ -674,16 +698,19 @@ var gDevToolsBrowser = exports.gDevTools
this._tabStats.histOpen.push(open);
this._tabStats.histPinned.push(pinned);
this._tabStats.peakOpen = Math.max(open, this._tabStats.peakOpen);
this._tabStats.peakPinned = Math.max(pinned, this._tabStats.peakPinned);
break;
case "TabSelect":
gDevToolsBrowser._updateMenuCheckbox();
break;
+ case "DOMContentLoaded":
+ gDevToolsBrowser._onBrowserWindowLoaded(event.target.defaultView);
+ break;
case "unload":
// top-level browser window unload
gDevToolsBrowser._forgetBrowserWindow(event.target.defaultView);
break;
}
},
_pingTelemetry: function () {
@@ -703,16 +730,17 @@ var gDevToolsBrowser = exports.gDevTools
this._telemetry.log(TABS_PINNED_AVG_HISTOGRAM, mean(tabStats.histPinned));
},
/**
* All browser windows have been closed, tidy up remaining objects.
*/
destroy: function () {
Services.prefs.removeObserver("devtools.", gDevToolsBrowser);
+ Services.ww.unregisterNotification(gDevToolsBrowser);
Services.obs.removeObserver(gDevToolsBrowser, "browser-delayed-startup-finished");
Services.obs.removeObserver(gDevToolsBrowser.destroy, "quit-application");
gDevToolsBrowser._pingTelemetry();
gDevToolsBrowser._telemetry = null;
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
gDevToolsBrowser._forgetBrowserWindow(win);
@@ -735,24 +763,26 @@ gDevTools.on("tool-unregistered", functi
}
gDevToolsBrowser._removeToolFromWindows(toolId);
});
gDevTools.on("toolbox-ready", gDevToolsBrowser._updateMenuCheckbox);
gDevTools.on("toolbox-destroyed", gDevToolsBrowser._updateMenuCheckbox);
Services.obs.addObserver(gDevToolsBrowser.destroy, "quit-application", false);
+Services.ww.registerNotification(gDevToolsBrowser);
Services.obs.addObserver(gDevToolsBrowser, "browser-delayed-startup-finished", false);
// Fake end of browser window load event for all already opened windows
// that is already fully loaded.
let enumerator = Services.wm.getEnumerator(gDevTools.chromeWindowType);
while (enumerator.hasMoreElements()) {
let win = enumerator.getNext();
if (win.gBrowserInit && win.gBrowserInit.delayedStartupFinished) {
+ gDevToolsBrowser._onBrowserWindowLoaded(win);
gDevToolsBrowser._registerBrowserWindow(win);
}
}
// Watch for module loader unload. Fires when the tools are reloaded.
unload(function () {
gDevToolsBrowser.destroy();
});