Bug 1382661 - Stop injecting DeveloperToolbar on top level windows. r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 20 Jul 2017 13:52:57 +0200
changeset 419184 ac0b38e566148e36369e7a7b987ba7b15b70e2ae
parent 419183 509be072f2ea0d9e6bef636e8ddcef1a15cf4a7a
child 419185 de668ab058ff8614980481e459fce96c44cb9342
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1382661
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1382661 - Stop injecting DeveloperToolbar on top level windows. r=jdescottes MozReview-Commit-ID: L6k7SPf8czd
devtools/client/commandline/test/helpers.js
devtools/client/framework/devtools-browser.js
devtools/client/menus.js
devtools/client/shared/developer-toolbar.js
devtools/client/shared/test/.eslintrc.js
devtools/client/shared/test/browser_toolbar_basic.js
devtools/client/shared/test/browser_toolbar_tooltip.js
devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js
devtools/client/webconsole/hudservice.js
--- a/devtools/client/commandline/test/helpers.js
+++ b/devtools/client/commandline/test/helpers.js
@@ -19,16 +19,17 @@
 // A copy of this code exists in firefox mochitests. They should be kept
 // in sync. Hence the exports synonym for non AMD contexts.
 var { helpers, assert } = (function () {
 
   var helpers = {};
 
   var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
   var { TargetFactory } = require("devtools/client/framework/target");
+  var { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
   var Services = require("Services");
 
   var assert = { ok: ok, is: is, log: info };
   var util = require("gcli/util/util");
   var cli = require("gcli/cli");
   var KeyEvent = require("gcli/util/util").KeyEvent;
 
   const { GcliFront } = require("devtools/shared/fronts/gcli");
@@ -206,18 +207,18 @@ var { helpers, assert } = (function () {
  * - requisition
  * @return A promise which resolves to the options object when the 'load' event
  * happens on the new tab
  */
   helpers.openToolbar = function (options) {
     options = options || {};
     options.chromeWindow = options.chromeWindow || window;
 
-    return options.chromeWindow.DeveloperToolbar.show(true).then(function () {
-      var toolbar = options.chromeWindow.DeveloperToolbar;
+    var toolbar = gDevToolsBrowser.getDeveloperToolbar(options.chromeWindow);
+    return toolbar.show(true).then(function () {
       options.automator = createDeveloperToolbarAutomator(toolbar);
       options.requisition = toolbar.requisition;
       return options;
     });
   };
 
 /**
  * Navigate the current tab to a URL
@@ -238,17 +239,18 @@ var { helpers, assert } = (function () {
   });
 
 /**
  * Undo the effects of |helpers.openToolbar|
  * @param options The options object passed to |helpers.openToolbar|
  * @return A promise resolved (with undefined) when the toolbar is closed
  */
   helpers.closeToolbar = function (options) {
-    return options.chromeWindow.DeveloperToolbar.hide().then(function () {
+    var toolbar = gDevToolsBrowser.getDeveloperToolbar(options.chromeWindow).hide();
+    return toolbar.then(function () {
       delete options.automator;
       delete options.requisition;
     });
   };
 
 /**
  * A helper to work with Task.spawn so you can do:
  *   return Task.spawn(realTestFunc).then(finish, helpers.handleError);
@@ -318,28 +320,28 @@ var { helpers, assert } = (function () {
  * As addTab, but that also opens the developer toolbar. In addition a new
  * 'automator' property is added to the options object which uses the
  * developer toolbar
  */
   helpers.addTabWithToolbar = function (url, callback, options) {
     return helpers.addTab(url, function (innerOptions) {
       var win = innerOptions.chromeWindow;
 
-      return win.DeveloperToolbar.show(true).then(function () {
-        var toolbar = win.DeveloperToolbar;
+      var toolbar = gDevToolsBrowser.getDeveloperToolbar(win);
+      return toolbar.show(true).then(function () {
         innerOptions.automator = createDeveloperToolbarAutomator(toolbar);
         innerOptions.requisition = toolbar.requisition;
 
         var reply = callback.call(null, innerOptions);
 
         return Promise.resolve(reply).catch(function (error) {
           ok(false, error);
           console.error(error);
         }).then(function () {
-          win.DeveloperToolbar.hide().then(function () {
+          toolbar.hide().then(function () {
             delete innerOptions.automator;
           });
         });
       });
     }, options);
   };
 
 /**
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -19,16 +19,17 @@ const {gDevTools} = require("./devtools"
 
 // Load target and toolbox lazily as they need gDevTools to be fully initialized
 loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
 loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
 loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
 loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/main", true);
 loader.lazyRequireGetter(this, "BrowserMenus", "devtools/client/framework/browser-menus");
 loader.lazyRequireGetter(this, "appendStyleSheet", "devtools/client/shared/stylesheet-utils", true);
+loader.lazyRequireGetter(this, "DeveloperToolbar", "devtools/client/shared/developer-toolbar", true);
 
 loader.lazyImporter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
 loader.lazyImporter(this, "CustomizableWidgets", "resource:///modules/CustomizableWidgets.jsm");
 loader.lazyImporter(this, "AppConstants", "resource://gre/modules/AppConstants.jsm");
 loader.lazyImporter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm");
 
 const {LocalizationHelper} = require("devtools/shared/l10n");
 const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
@@ -50,16 +51,21 @@ var gDevToolsBrowser = exports.gDevTools
   _trackedBrowserWindows: new Set(),
 
   /**
    * WeakMap keeping track of the devtools-browser stylesheets loaded in the various
    * tracked windows.
    */
   _browserStyleSheets: new WeakMap(),
 
+  /**
+   * WeakMap keeping track of DeveloperToolbar instances for each firefox window.
+   */
+  _toolbars: new WeakMap(),
+
   _tabStats: {
     peakOpen: 0,
     peakPinned: 0,
     histOpen: [],
     histPinned: []
   },
 
   /**
@@ -103,17 +109,17 @@ var gDevToolsBrowser = exports.gDevTools
     toggleMenuItem("menu_devToolbar", devToolbarEnabled);
     let focusEl = doc.getElementById("menu_devToolbar");
     if (devToolbarEnabled) {
       focusEl.removeAttribute("disabled");
     } else {
       focusEl.setAttribute("disabled", "true");
     }
     if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) {
-      win.DeveloperToolbar.show(false).catch(console.error);
+      this.getDeveloperToolbar(win).show(false).catch(console.error);
     }
 
     // Enable WebIDE?
     let webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled");
     toggleMenuItem("menu_webide", webIDEEnabled);
 
     if (webIDEEnabled) {
       gDevToolsBrowser.installWebIDEWidget();
@@ -494,36 +500,46 @@ var gDevToolsBrowser = exports.gDevTools
     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.updateDevtoolsThemeAttribute(win);
     this.ensurePrefObserver();
     win.addEventListener("unload", this);
 
     let tabContainer = win.gBrowser.tabContainer;
     tabContainer.addEventListener("TabSelect", this);
     tabContainer.addEventListener("TabOpen", this);
     tabContainer.addEventListener("TabClose", this);
     tabContainer.addEventListener("TabPinned", this);
     tabContainer.addEventListener("TabUnpinned", this);
   },
 
   /**
+   * Create singleton instance of the developer toolbar for a given top level window.
+   *
+   * @param {Window} win
+   *        The window to which the toolbar should be created.
+   */
+  getDeveloperToolbar(win) {
+    let toolbar = this._toolbars.get(win);
+    if (toolbar) {
+      return toolbar;
+    }
+    toolbar = new DeveloperToolbar(win);
+    this._toolbars.set(win, toolbar);
+    return toolbar;
+  },
+
+  /**
    * Hook the JS debugger tool to the "Debug Script" button of the slow script
    * dialog.
    */
   setSlowScriptDebugHandler() {
     let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
                          .getService(Ci.nsISlowScriptDebug);
     let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
 
@@ -722,21 +738,17 @@ var gDevToolsBrowser = exports.gDevTools
     }
 
     let styleSheet = this._browserStyleSheets.get(win);
     if (styleSheet) {
       styleSheet.remove();
       this._browserStyleSheets.delete(win);
     }
 
-    // Destroy the Developer toolbar if it has been accessed
-    let desc = Object.getOwnPropertyDescriptor(win, "DeveloperToolbar");
-    if (desc && !desc.get) {
-      win.DeveloperToolbar.destroy();
-    }
+    this._toolbars.delete(win);
 
     let tabContainer = win.gBrowser.tabContainer;
     tabContainer.removeEventListener("TabSelect", this);
     tabContainer.removeEventListener("TabOpen", this);
     tabContainer.removeEventListener("TabClose", this);
     tabContainer.removeEventListener("TabPinned", this);
     tabContainer.removeEventListener("TabUnpinned", this);
   },
--- a/devtools/client/menus.js
+++ b/devtools/client/menus.js
@@ -70,19 +70,19 @@ exports.menuitems = [
     l10nKey: "devToolbarMenu",
     disabled: true,
     oncommand(event) {
       let window = event.target.ownerDocument.defaultView;
       // Distinguish events when selecting a menuitem, where we either open
       // or close the toolbar and when hitting the key shortcut where we just
       // focus the toolbar if it doesn't already has it.
       if (event.target.tagName.toLowerCase() == "menuitem") {
-        window.DeveloperToolbar.toggle();
+        gDevToolsBrowser.getDeveloperToolbar(window).toggle();
       } else {
-        window.DeveloperToolbar.focusToggle();
+        gDevToolsBrowser.getDeveloperToolbar(window).focusToggle();
       }
     },
     key: {
       id: "devToolbar",
       modifiers: "shift"
     },
     checkbox: true
   },
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -225,17 +225,19 @@ DeveloperToolbar.prototype.createToolbar
   }
   let toolbar = this._doc.createElement("toolbar");
   toolbar.setAttribute("id", "developer-toolbar");
   toolbar.setAttribute("hidden", "true");
 
   let close = this._doc.createElement("toolbarbutton");
   close.setAttribute("id", "developer-toolbar-closebutton");
   close.setAttribute("class", "close-icon");
-  close.setAttribute("oncommand", "DeveloperToolbar.hide();");
+  close.addEventListener("command", (event) => {
+    this.hide();
+  });
   let closeTooltip = L10N.getStr("toolbar.closeButton.tooltip");
   close.setAttribute("tooltiptext", closeTooltip);
 
   let stack = this._doc.createElement("stack");
   stack.setAttribute("flex", "1");
 
   let input = this._doc.createElement("textbox");
   input.setAttribute("class", "gclitoolbar-input-node");
--- a/devtools/client/shared/test/.eslintrc.js
+++ b/devtools/client/shared/test/.eslintrc.js
@@ -1,9 +1,6 @@
 "use strict";
 
 module.exports = {
   // Extend from the shared list of defined globals for mochitests.
   "extends": "../../../.eslintrc.mochitests.js",
-  "globals": {
-    "DeveloperToolbar": true
-  }
 };
--- a/devtools/client/shared/test/browser_toolbar_basic.js
+++ b/devtools/client/shared/test/browser_toolbar_basic.js
@@ -1,27 +1,30 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the developer toolbar works properly
 
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
 const TEST_URI = TEST_URI_ROOT + "doc_toolbar_basic.html";
 
 add_task(function* () {
   info("Starting browser_toolbar_basic.js");
   yield addTab(TEST_URI);
 
-  ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in to start");
+  let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+  ok(!toolbar.visible, "DeveloperToolbar is not visible in to start");
 
-  let shown = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.SHOW);
+  let shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW);
   document.getElementById("menu_devToolbar").doCommand();
   yield shown;
-  ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in checkOpen");
+  ok(toolbar.visible, "DeveloperToolbar is visible in checkOpen");
 
   let close = document.getElementById("developer-toolbar-closebutton");
   ok(close, "Close button exists");
 
   let toggleToolbox =
     document.getElementById("menu_devToolbox");
   ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked");
 
@@ -31,30 +34,30 @@ add_task(function* () {
 
   yield addTab("about:blank");
   info("Opened a new tab");
 
   ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked");
 
   gBrowser.removeCurrentTab();
 
-  let hidden = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.HIDE);
+  let hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE);
   document.getElementById("menu_devToolbar").doCommand();
   yield hidden;
-  ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in hidden");
+  ok(!toolbar.visible, "DeveloperToolbar is not visible in hidden");
 
-  shown = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.SHOW);
+  shown = oneTimeObserve(toolbar.NOTIFICATIONS.SHOW);
   document.getElementById("menu_devToolbar").doCommand();
   yield shown;
-  ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in after open");
+  ok(toolbar.visible, "DeveloperToolbar is visible in after open");
 
   ok(isChecked(toggleToolbox), "toggle toolbox button is checked");
 
-  hidden = oneTimeObserve(DeveloperToolbar.NOTIFICATIONS.HIDE);
+  hidden = oneTimeObserve(toolbar.NOTIFICATIONS.HIDE);
   document.getElementById("developer-toolbar-closebutton").doCommand();
   yield hidden;
 
-  ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible after re-close");
+  ok(!toolbar.visible, "DeveloperToolbar is not visible after re-close");
 });
 
 function isChecked(b) {
   return b.getAttribute("checked") == "true";
 }
--- a/devtools/client/shared/test/browser_toolbar_tooltip.js
+++ b/devtools/client/shared/test/browser_toolbar_tooltip.js
@@ -1,99 +1,103 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the developer toolbar works properly
 
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
 const TEST_URI = "data:text/html;charset=utf-8,<p>Tooltip Tests</p>";
 const PREF_DEVTOOLS_THEME = "devtools.theme";
 
 registerCleanupFunction(() => {
   // Set preferences back to their original values
   Services.prefs.clearUserPref(PREF_DEVTOOLS_THEME);
 });
 
+let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+
 add_task(function* showToolbar() {
   yield addTab(TEST_URI);
 
   info("Starting browser_toolbar_tooltip.js");
 
-  ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in runTest");
+  ok(!toolbar.visible, "DeveloperToolbar is not visible in runTest");
 
-  let showPromise = observeOnce(DeveloperToolbar.NOTIFICATIONS.SHOW);
+  let showPromise = observeOnce(toolbar.NOTIFICATIONS.SHOW);
   document.getElementById("menu_devToolbar").doCommand();
   yield showPromise;
 });
 
 add_task(function* testDimensions() {
-  let tooltipPanel = DeveloperToolbar.tooltipPanel;
+  let tooltipPanel = toolbar.tooltipPanel;
 
-  DeveloperToolbar.focusManager.helpRequest();
-  yield DeveloperToolbar.inputter.setInput("help help");
+  toolbar.focusManager.helpRequest();
+  yield toolbar.inputter.setInput("help help");
 
-  DeveloperToolbar.inputter.setCursor({ start: "help help".length });
+  toolbar.inputter.setCursor({ start: "help help".length });
   is(tooltipPanel._dimensions.start, "help ".length,
           "search param start, when cursor at end");
   ok(getLeftMargin() > 30, "tooltip offset, when cursor at end");
 
-  DeveloperToolbar.inputter.setCursor({ start: "help".length });
+  toolbar.inputter.setCursor({ start: "help".length });
   is(tooltipPanel._dimensions.start, 0,
           "search param start, when cursor at end of command");
   ok(getLeftMargin() > 9, "tooltip offset, when cursor at end of command");
 
-  DeveloperToolbar.inputter.setCursor({ start: "help help".length - 1 });
+  toolbar.inputter.setCursor({ start: "help help".length - 1 });
   is(tooltipPanel._dimensions.start, "help ".length,
           "search param start, when cursor at penultimate position");
   ok(getLeftMargin() > 30, "tooltip offset, when cursor at penultimate position");
 
-  DeveloperToolbar.inputter.setCursor({ start: 0 });
+  toolbar.inputter.setCursor({ start: 0 });
   is(tooltipPanel._dimensions.start, 0,
           "search param start, when cursor at start");
   ok(getLeftMargin() > 9, "tooltip offset, when cursor at start");
 });
 
 add_task(function* testThemes() {
-  let tooltipPanel = DeveloperToolbar.tooltipPanel;
+  let tooltipPanel = toolbar.tooltipPanel;
   ok(tooltipPanel.document, "Tooltip panel is initialized");
 
   Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
 
-  yield DeveloperToolbar.inputter.setInput("");
-  yield DeveloperToolbar.inputter.setInput("help help");
+  yield toolbar.inputter.setInput("");
+  yield toolbar.inputter.setInput("help help");
   is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"),
      "dark", "Tooltip panel has correct theme");
 
   Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
 
-  yield DeveloperToolbar.inputter.setInput("");
-  yield DeveloperToolbar.inputter.setInput("help help");
+  yield toolbar.inputter.setInput("");
+  yield toolbar.inputter.setInput("help help");
   is(tooltipPanel.document.documentElement.getAttribute("devtoolstheme"),
      "light", "Tooltip panel has correct theme");
 });
 
 add_task(function* hideToolbar() {
   info("Ending browser_toolbar_tooltip.js");
-  yield DeveloperToolbar.inputter.setInput("");
+  yield toolbar.inputter.setInput("");
 
-  ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in hideToolbar");
+  ok(toolbar.visible, "DeveloperToolbar is visible in hideToolbar");
 
   info("Hide toolbar");
-  let hidePromise = observeOnce(DeveloperToolbar.NOTIFICATIONS.HIDE);
+  let hidePromise = observeOnce(toolbar.NOTIFICATIONS.HIDE);
   document.getElementById("menu_devToolbar").doCommand();
   yield hidePromise;
 
-  ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible in hideToolbar");
+  ok(!toolbar.visible, "DeveloperToolbar is not visible in hideToolbar");
 
   info("Done test");
 });
 
 function getLeftMargin() {
-  let style = DeveloperToolbar.tooltipPanel._panel.style.marginLeft;
+  let style = toolbar.tooltipPanel._panel.style.marginLeft;
   return parseInt(style.slice(0, -2), 10);
 }
 
 function observeOnce(topic, ownsWeak = false) {
   return new Promise(function (resolve, reject) {
     let resolver = function (subject) {
       Services.obs.removeObserver(resolver, topic);
       resolve(subject);
--- a/devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js
+++ b/devtools/client/shared/test/browser_toolbar_webconsole_errors_count.js
@@ -2,24 +2,28 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* eslint-disable mozilla/no-cpows-in-tests */
 
 "use strict";
 
 // Tests that the developer toolbar errors count works properly.
 
+const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+
 // Use the old webconsole since this is directly accessing old DOM, and
 // the error count isn't reset when pressing the clear button in new one
 // See Bug 1304794.
 Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false);
 registerCleanupFunction(function* () {
   Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
 });
 
+let toolbar = gDevToolsBrowser.getDeveloperToolbar(window);
+
 function test() {
   const TEST_URI = TEST_URI_ROOT + "doc_toolbar_webconsole_errors_count.html";
 
   let tab1, tab2, webconsole;
 
   Services.prefs.setBoolPref("javascript.options.strict", true);
 
   registerCleanupFunction(() => {
@@ -30,25 +34,25 @@ function test() {
   addTab(TEST_URI).then(openToolbar);
 
   function openToolbar(tab) {
     tab1 = tab;
     ignoreAllUncaughtExceptions(false);
 
     expectUncaughtException();
 
-    if (!DeveloperToolbar.visible) {
-      DeveloperToolbar.show(true).then(onOpenToolbar);
+    if (!toolbar.visible) {
+      toolbar.show(true).then(onOpenToolbar);
     } else {
       onOpenToolbar();
     }
   }
 
   function onOpenToolbar() {
-    ok(DeveloperToolbar.visible, "DeveloperToolbar is visible");
+    ok(toolbar.visible, "DeveloperToolbar is visible");
     webconsole = document.getElementById("developer-toolbar-toolbox-button");
 
     waitForButtonUpdate({
       name: "web console button shows page errors",
       errors: 3,
       warnings: 0,
       callback: addErrors,
     });
@@ -235,19 +239,19 @@ function test() {
         // Get out of the toolbar event execution loop.
         executeSoon(options.callback);
       }
       return result;
     }
 
     if (!check()) {
       info("wait for: " + options.name);
-      DeveloperToolbar.on("errors-counter-updated", function onUpdate(event) {
+      toolbar.on("errors-counter-updated", function onUpdate(event) {
         if (check()) {
-          DeveloperToolbar.off(event, onUpdate);
+          toolbar.off(event, onUpdate);
         }
       });
     }
   }
 
   function openWebConsole(tab, callback) {
     let target = TargetFactory.forTab(tab);
     gDevTools.showToolbox(target, "webconsole").then((toolbox) =>
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const {extend} = require("devtools/shared/extend");
 var {TargetFactory} = require("devtools/client/framework/target");
+var {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
 var {Tools} = require("devtools/client/definitions");
 const { Task } = require("devtools/shared/task");
 var promise = require("promise");
 var Services = require("Services");
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
 loader.lazyRequireGetter(this, "NewWebConsoleFrame", "devtools/client/webconsole/new-webconsole", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
@@ -384,17 +385,18 @@ WebConsole.prototype = {
 
   /**
    * The clear output button handler.
    * @private
    */
   _onClearButton: function WC__onClearButton()
   {
     if (this.target.isLocalTab) {
-      this.browserWindow.DeveloperToolbar.resetErrorsCount(this.target.tab);
+      gDevToolsBrowser.getDeveloperToolbar(this.browserWindow)
+        .resetErrorsCount(this.target.tab);
     }
   },
 
   /**
    * Alias for the WebConsoleFrame.setFilterState() method.
    * @see webconsole.js::WebConsoleFrame.setFilterState()
    */
   setFilterState: function WC_setFilterState()