Bug 912057 - Replace Browser Debugger with Browser Toolbox. r=past
authorJ. Ryan Stinnett <jryans@gmail.com>
Mon, 02 Dec 2013 02:28:01 -0600
changeset 158375 677a76d18d505c372e83c6c63853ecfdf6987aa5
parent 158374 236a0eba3a8afdbb6e72085b19cbbd6941b83397
child 158376 6efabfb144b1cc0864fb4ce877534107965b0728
push id25742
push userryanvm@gmail.com
push dateMon, 02 Dec 2013 21:43:04 +0000
treeherdermozilla-central@c93cfe704487 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspast
bugs912057
milestone28.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 912057 - Replace Browser Debugger with Browser Toolbox. r=past
browser/base/content/browser-menubar.inc
browser/base/content/browser-sets.inc
browser/base/content/browser.js
browser/devtools/app-manager/content/index.js
browser/devtools/debugger/DebuggerProcess.jsm
browser/devtools/debugger/test/head.js
browser/devtools/devtools-clhandler.js
browser/devtools/framework/ToolboxProcess.jsm
browser/devtools/framework/gDevTools.jsm
browser/devtools/framework/test/browser_dynamic_tool_enabling.js
browser/devtools/framework/toolbox-hosts.js
browser/devtools/framework/toolbox-process-window.js
browser/devtools/framework/toolbox-process-window.xul
browser/devtools/jar.mn
browser/devtools/webconsole/hudservice.js
browser/locales/en-US/chrome/browser/browser.dtd
toolkit/devtools/server/actors/inspector.js
toolkit/devtools/server/actors/root.js
toolkit/devtools/server/actors/styleeditor.js
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -513,19 +513,19 @@
                             accesskey="&devToolboxMenuItem.accesskey;"/>
                   <menuseparator id="menu_devtools_separator"/>
                   <menuitem id="menu_devToolbar"
                             observes="devtoolsMenuBroadcaster_DevToolbar"
                             accesskey="&devToolbarMenu.accesskey;"/>
                   <menuitem id="menu_devAppMgr"
                             observes="devtoolsMenuBroadcaster_DevAppMgr"
                             accesskey="&devAppMgrMenu.accesskey;"/>
-                  <menuitem id="menu_chromeDebugger"
-                            observes="devtoolsMenuBroadcaster_ChromeDebugger"
-                            accesskey="&chromeDebuggerMenu.accesskey;"/>
+                  <menuitem id="menu_browserToolbox"
+                            observes="devtoolsMenuBroadcaster_BrowserToolbox"
+                            accesskey="&browserToolboxMenu.accesskey;"/>
                   <menuitem id="menu_browserConsole"
                             observes="devtoolsMenuBroadcaster_BrowserConsole"
                             accesskey="&browserConsoleCmd.accesskey;"/>
                   <menuitem id="menu_responsiveUI"
                             observes="devtoolsMenuBroadcaster_ResponsiveUI"
                             accesskey="&responsiveDesignTool.accesskey;"/>
                   <menuitem id="menu_scratchpad"
                             observes="devtoolsMenuBroadcaster_Scratchpad"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -90,17 +90,17 @@
     <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
     <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/>
     <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/>
     <command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/>
-    <command id="Tools:ChromeDebugger" oncommand="BrowserDebuggerProcess.init();" disabled="true" hidden="true"/>
+    <command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
     <command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
     <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
@@ -180,19 +180,19 @@
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
                  label="&devToolbarMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbar"
                  key="key_devToolbar"/>
     <broadcaster id="devtoolsMenuBroadcaster_DevAppMgr"
                  label="&devAppMgrMenu.label;"
                  command="Tools:DevAppMgr"/>
-    <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
-                 label="&chromeDebuggerMenu.label;"
-                 command="Tools:ChromeDebugger"/>
+    <broadcaster id="devtoolsMenuBroadcaster_BrowserToolbox"
+                 label="&browserToolboxMenu.label;"
+                 command="Tools:BrowserToolbox"/>
     <broadcaster id="devtoolsMenuBroadcaster_BrowserConsole"
                  label="&browserConsoleCmd.label;"
                  key="key_browserConsole"
                  command="Tools:BrowserConsole"/>
     <broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
                  label="&scratchpad.label;"
                  command="Tools:Scratchpad"
                  key="key_scratchpad"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -112,20 +112,20 @@ XPCOMUtils.defineLazyGetter(this, "Popup
 });
 
 XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", tmp);
   return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
 });
 
-XPCOMUtils.defineLazyGetter(this, "BrowserDebuggerProcess", function() {
+XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() {
   let tmp = {};
-  Cu.import("resource:///modules/devtools/DebuggerProcess.jsm", tmp);
-  return tmp.BrowserDebuggerProcess;
+  Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", tmp);
+  return tmp.BrowserToolboxProcess;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "Social",
   "resource:///modules/Social.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
   "resource://gre/modules/PageThumbs.jsm");
 
--- a/browser/devtools/app-manager/content/index.js
+++ b/browser/devtools/app-manager/content/index.js
@@ -62,16 +62,19 @@ let UI = {
           this.selectTab("projects");
           break;
         case "toolbox-raise":
           this.selectTab(json.uid);
           break;
         case "toolbox-close":
           this.closeToolboxTab(json.uid);
           break;
+        case "toolbox-title":
+          // Not implemented
+          break;
         default:
           Cu.reportError("Unknown message: " + json.name);
       }
     } catch(e) { Cu.reportError(e); }
 
     // Forward message
     let panels = document.querySelectorAll(".panel");
     for (let frame of panels) {
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -12,17 +12,17 @@ let { Services } = Cu.import("resource:/
 let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 Services.prefs.setBoolPref("devtools.debugger.log", false);
 
 let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 let { Promise: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
-let { BrowserDebuggerProcess } = Cu.import("resource:///modules/devtools/DebuggerProcess.jsm", {});
+let { BrowserToolboxProcess } = Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {});
 let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
 let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
 let { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/";
 
@@ -468,19 +468,19 @@ function initDebugger(aTarget, aWindow) 
   });
 }
 
 function initChromeDebugger(aOnClose) {
   info("Initializing a chrome debugger process.");
 
   let deferred = promise.defer();
 
-  // Wait for the debugger process to start...
-  BrowserDebuggerProcess.init(aOnClose, aProcess => {
-    info("Chrome debugger process started successfully.");
+  // Wait for the toolbox process to start...
+  BrowserToolboxProcess.init(aOnClose, aProcess => {
+    info("Browser toolbox process started successfully.");
 
     prepareDebugger(aProcess);
     deferred.resolve(aProcess);
   });
 
   return deferred.promise;
 }
 
--- a/browser/devtools/devtools-clhandler.js
+++ b/browser/devtools/devtools-clhandler.js
@@ -47,31 +47,31 @@ devtoolsCommandlineHandler.prototype = {
     let remoteDebuggingEnabled = false;
     try {
       remoteDebuggingEnabled = kDebuggerPrefs.every((pref) => Services.prefs.getBoolPref(pref));
     } catch (ex) {
       Cu.reportError(ex);
       return;
     }
     if (remoteDebuggingEnabled) {
-      Cu.import("resource:///modules/devtools/DebuggerProcess.jsm");
-      BrowserDebuggerProcess.init();
+      Cu.import("resource:///modules/devtools/ToolboxProcess.jsm");
+      BrowserToolboxProcess.init();
     } else {
       let errorMsg = "Could not run chrome debugger! You need the following prefs " +
                      "to be set to true: " + kDebuggerPrefs.join(", ");
       Cu.reportError(errorMsg);
       // Dump as well, as we're doing this from a commandline, make sure people don't miss it:
       dump(errorMsg + "\n");
     }
 
     if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
       cmdLine.preventDefault = true;
     }
   },
 
   helpInfo : "  -jsconsole         Open the Browser Console.\n" +
-             "  -jsdebugger        Open the Browser Debugger.\n",
+             "  -jsdebugger        Open the Browser Toolbox.\n",
 
   classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);
rename from browser/devtools/debugger/DebuggerProcess.jsm
rename to browser/devtools/framework/ToolboxProcess.jsm
--- a/browser/devtools/debugger/DebuggerProcess.jsm
+++ b/browser/devtools/framework/ToolboxProcess.jsm
@@ -2,60 +2,60 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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";
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
-const DBG_XUL = "chrome://browser/content/devtools/debugger.xul";
+const DBG_XUL = "chrome://browser/content/devtools/framework/toolbox-process-window.xul";
 const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 let require = devtools.require;
 let Telemetry = require("devtools/shared/telemetry");
 
-this.EXPORTED_SYMBOLS = ["BrowserDebuggerProcess"];
+this.EXPORTED_SYMBOLS = ["BrowserToolboxProcess"];
 
 /**
- * Constructor for creating a process that will hold a chrome debugger.
+ * Constructor for creating a process that will hold a chrome toolbox.
  *
  * @param function aOnClose [optional]
  *        A function called when the process stops running.
  * @param function aOnRun [optional]
  *        A function called when the process starts running.
  */
-this.BrowserDebuggerProcess = function BrowserDebuggerProcess(aOnClose, aOnRun) {
+this.BrowserToolboxProcess = function BrowserToolboxProcess(aOnClose, aOnRun) {
   this._closeCallback = aOnClose;
   this._runCallback = aOnRun;
   this._telemetry = new Telemetry();
 
   this._initServer();
   this._initProfile();
   this._create();
 };
 
 /**
- * Initializes and starts a chrome debugger process.
+ * Initializes and starts a chrome toolbox process.
  * @return object
  */
-BrowserDebuggerProcess.init = function(aOnClose, aOnRun) {
-  return new BrowserDebuggerProcess(aOnClose, aOnRun);
+BrowserToolboxProcess.init = function(aOnClose, aOnRun) {
+  return new BrowserToolboxProcess(aOnClose, aOnRun);
 };
 
-BrowserDebuggerProcess.prototype = {
+BrowserToolboxProcess.prototype = {
   /**
    * Initializes the debugger server.
    */
   _initServer: function() {
-    dumpn("Initializing the chrome debugger server.");
+    dumpn("Initializing the chrome toolbox server.");
 
     if (!this.loader) {
       // Create a separate loader instance, so that we can be sure to receive a
       // separate instance of the DebuggingServer from the rest of the devtools.
       // This allows us to safely use the tools against even the actors and
       // DebuggingServer itself.
       this.loader = new DevToolsLoader();
       this.loader.main("devtools/server/main");
@@ -66,73 +66,73 @@ BrowserDebuggerProcess.prototype = {
     if (!this.debuggerServer.initialized) {
       this.debuggerServer.init();
       this.debuggerServer.addBrowserActors();
       dumpn("initialized and added the browser actors for the DebuggerServer.");
     }
 
     this.debuggerServer.openListener(Prefs.chromeDebuggingPort);
 
-    dumpn("Finished initializing the chrome debugger server.");
+    dumpn("Finished initializing the chrome toolbox server.");
     dumpn("Started listening on port: " + Prefs.chromeDebuggingPort);
   },
 
   /**
    * Initializes a profile for the remote debugger process.
    */
   _initProfile: function() {
-    dumpn("Initializing the chrome debugger user profile.");
+    dumpn("Initializing the chrome toolbox user profile.");
 
     let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
       .createInstance(Ci.nsIToolkitProfileService);
 
     let profileName;
     try {
       // Attempt to get the required chrome debugging profile name string.
       profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
-      dumpn("Using chrome debugger profile name: " + profileName);
+      dumpn("Using chrome toolbox profile name: " + profileName);
     } catch (e) {
       // Requested profile string could not be retrieved.
       profileName = CHROME_DEBUGGER_PROFILE_NAME;
       let msg = "Querying the current profile failed. " + e.name + ": " + e.message;
       dumpn(msg);
       Cu.reportError(msg);
     }
 
     let profileObject;
     try {
       // Attempt to get the required chrome debugging profile toolkit object.
       profileObject = profileService.getProfileByName(profileName);
-      dumpn("Using chrome debugger profile object: " + profileObject);
+      dumpn("Using chrome toolbox profile object: " + profileObject);
 
       // The profile exists but the corresponding folder may have been deleted.
       var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
       while (enumerator.hasMoreElements()) {
         let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
         if (profileDir.leafName.contains(profileName)) {
           // Requested profile was found and the folder exists.
           this._dbgProfile = profileObject;
           return;
         }
       }
       // Requested profile was found but the folder was deleted. Cleanup needed.
       profileObject.remove(true);
-      dumpn("The already existing chrome debugger profile was invalid.");
+      dumpn("The already existing chrome toolbox profile was invalid.");
     } catch (e) {
       // Requested profile object was not found.
       let msg = "Creating a profile failed. " + e.name + ": " + e.message;
       dumpn(msg);
       Cu.reportError(msg);
     }
 
     // Create a new chrome debugging profile.
     this._dbgProfile = profileService.createProfile(null, profileName);
     profileService.flush();
 
-    dumpn("Finished creating the chrome debugger user profile.");
+    dumpn("Finished creating the chrome toolbox user profile.");
     dumpn("Flushed profile service with: " + profileName);
   },
 
   /**
    * Creates and initializes the profile & process for the remote debugger.
    */
   _create: function() {
     dumpn("Initializing chrome debugging process.");
@@ -140,17 +140,17 @@ BrowserDebuggerProcess.prototype = {
     process.init(Services.dirsvc.get("XREExeF", Ci.nsIFile));
 
     dumpn("Running chrome debugging process.");
     let args = ["-no-remote", "-foreground", "-P", this._dbgProfile.name, "-chrome", DBG_XUL];
     process.runwAsync(args, args.length, { observe: () => this.close() });
 
     this._telemetry.toolOpened("jsbrowserdebugger");
 
-    dumpn("Chrome debugger is now running...");
+    dumpn("Chrome toolbox is now running...");
     if (typeof this._runCallback == "function") {
       this._runCallback.call({}, this);
     }
   },
 
   /**
    * Closes the remote debugger, removing the profile and killing the process.
    */
@@ -159,17 +159,17 @@ BrowserDebuggerProcess.prototype = {
 
     if (this._dbgProcess.isRunning) {
       this._dbgProcess.kill();
     }
 
     this._telemetry.toolClosed("jsbrowserdebugger");
     this.debuggerServer.destroy();
 
-    dumpn("Chrome debugger is now closed...");
+    dumpn("Chrome toolbox is now closed...");
     if (typeof this._closeCallback == "function") {
       this._closeCallback.call({}, this);
     }
   }
 };
 
 /**
  * Shortcuts for accessing various debugger preferences.
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -400,22 +400,22 @@ let gDevToolsBrowser = {
     if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) {
       win.DeveloperToolbar.show(false);
     }
 
     // Enable App Manager?
     let appMgrEnabled = Services.prefs.getBoolPref("devtools.appmanager.enabled");
     toggleCmd("Tools:DevAppMgr", appMgrEnabled);
 
-    // Enable Chrome Debugger?
+    // Enable Browser Toolbox?
     let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled");
     let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled");
     let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled &&
                         Services.prefs.getBoolPref("devtools.debugger.chrome-enabled");
-    toggleCmd("Tools:ChromeDebugger", remoteEnabled);
+    toggleCmd("Tools:BrowserToolbox", remoteEnabled);
 
     // Enable Error Console?
     let consoleEnabled = Services.prefs.getBoolPref("devtools.errorconsole.enabled");
     toggleCmd("Tools:ErrorConsole", consoleEnabled);
 
     // Enable DevTools connection screen, if the preference allows this.
     toggleCmd("Tools:DevToolsConnect", devtoolsRemoteEnabled);
   },
--- a/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
+++ b/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that toggling prefs immediately (de)activates the relevant menuitem
 
 let gItemsToTest = {
   "menu_devToolbar": "devtools.toolbar.enabled",
   "menu_devAppMgr": "devtools.appmanager.enabled",
-  "menu_chromeDebugger": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"],
+  "menu_browserToolbox": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"],
   "javascriptConsole": "devtools.errorconsole.enabled",
   "menu_devtools_connect": "devtools.debugger.remote-enabled",
 };
 
 function expectedAttributeValueFromPrefs(prefs) {
   return prefs.every((pref) => Services.prefs.getBoolPref(pref)) ?
          "" : "true";
 }
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -21,17 +21,17 @@ Cu.import("resource:///modules/devtools/
  * destroy() - destroy the host's UI
  */
 
 exports.Hosts = {
   "bottom": BottomHost,
   "side": SidebarHost,
   "window": WindowHost,
   "custom": CustomHost
-}
+};
 
 /**
  * Host object for the dock on the bottom of the browser
  */
 function BottomHost(hostTab) {
   this.hostTab = hostTab;
 
   EventEmitter.decorate(this);
@@ -267,35 +267,38 @@ WindowHost.prototype = {
       this._destroyed = true;
 
       this._window.removeEventListener("unload", this._boundUnload);
       this._window.close();
     }
 
     return promise.resolve(null);
   }
-}
+};
 
 /**
  * Host object for the toolbox in its own tab
  */
 function CustomHost(hostTab, options) {
   this.frame = options.customIframe;
   this.uid = options.uid;
   EventEmitter.decorate(this);
 }
 
 CustomHost.prototype = {
   type: "custom",
 
-  _sendMessageToTopWindow: function CH__sendMessageToTopWindow(msg) {
+  _sendMessageToTopWindow: function CH__sendMessageToTopWindow(msg, data) {
     // It's up to the custom frame owner (parent window) to honor
     // "close" or "raise" instructions.
     let topWindow = this.frame.ownerDocument.defaultView;
-    let json = {name:"toolbox-" + msg, uid: this.uid}
+    let json = {name:"toolbox-" + msg, uid: this.uid};
+    if (data) {
+      json.data = data;
+    }
     topWindow.postMessage(JSON.stringify(json), "*");
   },
 
   /**
    * Create a new xul window to contain the toolbox.
    */
   create: function CH_create() {
     return promise.resolve(this.frame);
@@ -307,17 +310,17 @@ CustomHost.prototype = {
   raise: function CH_raise() {
     this._sendMessageToTopWindow("raise");
   },
 
   /**
    * Set the toolbox title.
    */
   setTitle: function CH_setTitle(title) {
-    // Not supported
+    this._sendMessageToTopWindow("title", { value: title });
   },
 
   /**
    * Destroy the window.
    */
   destroy: function WH_destroy() {
     if (!this._destroyed) {
       this._destroyed = true;
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox-process-window.js
@@ -0,0 +1,103 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
+let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+let { debuggerSocketConnect, DebuggerClient } =
+  Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
+let { ViewHelpers } =
+  Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
+
+/**
+ * Shortcuts for accessing various debugger preferences.
+ */
+let Prefs = new ViewHelpers.Prefs("devtools.debugger", {
+  chromeDebuggingHost: ["Char", "chrome-debugging-host"],
+  chromeDebuggingPort: ["Int", "chrome-debugging-port"]
+});
+
+// Initiate the connection
+let transport = debuggerSocketConnect(
+  Prefs.chromeDebuggingHost,
+  Prefs.chromeDebuggingPort
+);
+let client = new DebuggerClient(transport);
+client.connect(() => {
+  client.listTabs(openToolbox);
+});
+
+let gToolbox;
+
+function openToolbox(form) {
+  let options = {
+    form: form,
+    client: client,
+    chrome: true
+  };
+  devtools.TargetFactory.forRemoteTab(options).then(target => {
+    let frame = document.getElementById("toolbox-iframe");
+    let options = { customIframe: frame };
+    gDevTools.showToolbox(target,
+                          "jsdebugger",
+                          devtools.Toolbox.HostType.CUSTOM,
+                          options)
+             .then(onNewToolbox);
+  });
+}
+
+function onNewToolbox(toolbox) {
+   gToolbox = toolbox;
+   bindToolboxHandlers();
+   raise();
+}
+
+function bindToolboxHandlers() {
+  gToolbox.once("destroyed", quitApp);
+  window.addEventListener("unload", onUnload);
+}
+
+function onUnload() {
+  window.removeEventListener("unload", onUnload);
+  window.removeEventListener("message", onMessage);
+  gToolbox.destroy();
+}
+
+function onMessage(event) {
+  try {
+    let json = JSON.parse(event.data);
+    switch (json.name) {
+      case "toolbox-raise":
+        raise();
+        break;
+      case "toolbox-title":
+        setTitle(json.data.value);
+        break;
+    }
+  } catch(e) { Cu.reportError(e); }
+}
+
+window.addEventListener("message", onMessage);
+
+function raise() {
+  window.focus();
+}
+
+function setTitle(title) {
+  document.title = title;
+}
+
+function quitApp() {
+  let quit = Cc["@mozilla.org/supports-PRBool;1"]
+             .createInstance(Ci.nsISupportsPRBool);
+  Services.obs.notifyObservers(quit, "quit-application-requested", null);
+
+  let shouldProceed = !quit.data;
+  if (shouldProceed) {
+    Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox-process-window.xul
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - 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/. -->
+<!DOCTYPE window [
+<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" >
+ %toolboxDTD;
+]>
+
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        id="devtools-toolbox-window"
+        macanimationtype="document"
+        fullscreenbutton="true"
+        windowtype="devtools:toolbox"
+        width="900" height="600"
+        persist="screenX screenY width height sizemode">
+
+  <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
+  <script type="text/javascript" src="toolbox-process-window.js"/>
+  <script type="text/javascript" src="chrome://global/content/viewSourceUtils.js"/>
+  <script type="text/javascript" src="chrome://browser/content/utilityOverlay.js"/>
+
+  <commandset id="toolbox-commandset">
+    <command id="toolbox-cmd-close" oncommand="window.close();"/>
+  </commandset>
+
+  <keyset id="toolbox-keyset">
+    <key id="toolbox-key-close"
+         key="&closeCmd.key;"
+         command="toolbox-cmd-close"
+         modifiers="accel"/>
+  </keyset>
+
+  <!-- This will be used by the Web Console to hold any popups it may create,
+       for example when viewing network request details. -->
+  <popupset id="mainPopupSet"></popupset>
+
+  <iframe id="toolbox-iframe" flex="1"></iframe>
+</window>
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -71,16 +71,18 @@ browser.jar:
     content/browser/devtools/commandline.css                           (commandline/commandline.css)
     content/browser/devtools/commandlineoutput.xhtml                   (commandline/commandlineoutput.xhtml)
     content/browser/devtools/commandlinetooltip.xhtml                  (commandline/commandlinetooltip.xhtml)
     content/browser/devtools/framework/toolbox-window.xul              (framework/toolbox-window.xul)
     content/browser/devtools/framework/toolbox-options.xul             (framework/toolbox-options.xul)
     content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
 *   content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
     content/browser/devtools/framework/toolbox.css                     (framework/toolbox.css)
+    content/browser/devtools/framework/toolbox-process-window.xul      (framework/toolbox-process-window.xul)
+    content/browser/devtools/framework/toolbox-process-window.js       (framework/toolbox-process-window.js)
     content/browser/devtools/inspector/inspector.xul                   (inspector/inspector.xul)
     content/browser/devtools/inspector/inspector.css                   (inspector/inspector.css)
     content/browser/devtools/connect.xhtml                             (framework/connect/connect.xhtml)
     content/browser/devtools/connect.css                               (framework/connect/connect.css)
     content/browser/devtools/connect.js                                (framework/connect/connect.js)
     content/browser/devtools/app-manager/template.js                   (app-manager/content/template.js)
     content/browser/devtools/app-manager/utils.js                      (app-manager/content/utils.js)
     content/browser/devtools/app-manager/connection-footer.js          (app-manager/content/connection-footer.js)
--- a/browser/devtools/webconsole/hudservice.js
+++ b/browser/devtools/webconsole/hudservice.js
@@ -331,34 +331,53 @@ WebConsole.prototype = {
    * by unit tests. The callback takes one argument: the HTTP activity object as
    * received from the remote Web Console.
    *
    * @type function
    */
   get lastFinishedRequestCallback() HUDService.lastFinishedRequest.callback,
 
   /**
+   * Getter for the window that can provide various utilities that the web
+   * console makes use of, like opening links, managing popups, etc.  In
+   * most cases, this will be |this.browserWindow|, but in some uses (such as
+   * the Browser Toolbox), there is no browser window, so an alternative window
+   * hosts the utilities there.
+   * @type nsIDOMWindow
+   */
+  get chromeUtilsWindow()
+  {
+    if (this.browserWindow) {
+      return this.browserWindow;
+    }
+    return this.chromeWindow.top;
+  },
+
+  /**
    * Getter for the xul:popupset that holds any popups we open.
    * @type nsIDOMElement
    */
   get mainPopupSet()
   {
-    return this.browserWindow.document.getElementById("mainPopupSet");
+    return this.chromeUtilsWindow.document.getElementById("mainPopupSet");
   },
 
   /**
    * Getter for the output element that holds messages we display.
    * @type nsIDOMElement
    */
   get outputNode()
   {
     return this.ui ? this.ui.outputNode : null;
   },
 
-  get gViewSourceUtils() this.browserWindow.gViewSourceUtils,
+  get gViewSourceUtils()
+  {
+    return this.chromeUtilsWindow.gViewSourceUtils;
+  },
 
   /**
    * Initialize the Web Console instance.
    *
    * @return object
    *         A promise for the initialization.
    */
   init: function WC_init()
@@ -411,17 +430,17 @@ WebConsole.prototype = {
   /**
    * Open a link in a new tab.
    *
    * @param string aLink
    *        The URL you want to open in a new tab.
    */
   openLink: function WC_openLink(aLink)
   {
-    this.browserWindow.openUILinkIn(aLink, "tab");
+    this.chromeUtilsWindow.openUILinkIn(aLink, "tab");
   },
 
   /**
    * Open a link in Firefox's view source.
    *
    * @param string aSourceURL
    *        The URL of the file.
    * @param integer aSourceLine
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -239,20 +239,20 @@ These should match what Safari and other
   -  "Scratchpad" in your locale. You should feel free to find a close
   -  approximation to it or choose a word (or words) that means
   -  "simple discardable text editor". -->
 <!ENTITY scratchpad.label             "Scratchpad">
 <!ENTITY scratchpad.accesskey         "s">
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
-<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the
-  -  application menu item that opens the browser debugger UI in the Tools menu. -->
-<!ENTITY chromeDebuggerMenu.label       "Browser Debugger">
-<!ENTITY chromeDebuggerMenu.accesskey   "e">
+<!-- LOCALIZATION NOTE (browserToolboxMenu.label): This is the label for the
+  -  application menu item that opens the browser toolbox UI in the Tools menu. -->
+<!ENTITY browserToolboxMenu.label     "Browser Toolbox">
+<!ENTITY browserToolboxMenu.accesskey "e">
 
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
 <!ENTITY devToolbarMenu.label              "Developer Toolbar">
 <!ENTITY devToolbarMenu.accesskey          "v">
 <!ENTITY devAppMgrMenu.label               "App Manager">
 <!ENTITY devAppMgrMenu.accesskey           "a">
 <!ENTITY devToolbar.keycode                "VK_F2">
 <!ENTITY devToolbar.keytext                "F2">
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -76,20 +76,22 @@ HELPER_SHEET += ":-moz-devtools-highligh
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
 
 loader.lazyGetter(this, "DOMParser", function() {
  return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
 });
 
 exports.register = function(handle) {
+  handle.addGlobalActor(InspectorActor, "inspectorActor");
   handle.addTabActor(InspectorActor, "inspectorActor");
 };
 
 exports.unregister = function(handle) {
+  handle.removeGlobalActor(InspectorActor);
   handle.removeTabActor(InspectorActor);
 };
 
 // XXX: A poor man's makeInfallible until we move it out of transport.js
 // Which should be very soon.
 function makeInfallible(handler) {
   return function(...args) {
     try {
--- a/toolkit/devtools/server/actors/root.js
+++ b/toolkit/devtools/server/actors/root.js
@@ -187,16 +187,21 @@ RootActor.prototype = {
   get isRootActor() true,
 
   /**
    * The (chrome) window, for use by child actors
    */
   get window() Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType),
 
   /**
+   * URL of the chrome window.
+   */
+  get url() { return this.window ? this.window.document.location.href : null; },
+
+  /**
    * Getter for the best nsIWebProgress for to watching this window.
    */
   get webProgress() {
     return this.window
       .QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDocShell)
       .QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIWebProgress);
@@ -270,16 +275,21 @@ RootActor.prototype = {
       this.conn.addActorPool(this._tabActorPool);
 
       let reply = {
         "from": this.actorID,
         "selected": selected || 0,
         "tabs": [actor.form() for (actor of tabActorList)],
       };
 
+      /* If a root window is accessible, include its URL. */
+      if (this.url) {
+        reply.url = this.url;
+      }
+
       /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */
       this._appendExtraActors(reply);
 
       /*
        * Now that we're actually going to report the contents of tabList to
        * the client, we're responsible for letting the client know if it
        * changes.
        */
--- a/toolkit/devtools/server/actors/styleeditor.js
+++ b/toolkit/devtools/server/actors/styleeditor.js
@@ -701,12 +701,13 @@ StyleSheetActor.prototype = {
 
 StyleSheetActor.prototype.requestTypes = {
   "toggleDisabled": StyleSheetActor.prototype.onToggleDisabled,
   "fetchSource": StyleSheetActor.prototype.onFetchSource,
   "update": StyleSheetActor.prototype.onUpdate
 };
 
 DebuggerServer.addTabActor(StyleEditorActor, "styleEditorActor");
+DebuggerServer.addGlobalActor(StyleEditorActor, "styleEditorActor");
 
 XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });