Merge fx-team to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 02 Dec 2013 16:43:03 -0500
changeset 174012 c93cfe704487cf493fc4f289e015f068e49c4644
parent 173986 492fbc8095b807132f96446fcc6a8db62faf9ff8 (current diff)
parent 174011 2d4fd5a493b172750da02e2ecf0e929576ed8a82 (diff)
child 174013 0ce73a4540df107c04a95bbabacb47e77f62ec38
child 174019 cf52d24c12b678104d08adec2b82c82a908e257f
child 174040 612b104050ce2fe75aca45f1754a7740a6691ddb
child 174063 4fda28f9e2597bb0df620e092ae2f6e19f132136
child 174093 a06f7b3bb7f7b7def2806e641215bb2bb60b7ccf
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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
Merge fx-team to m-c.
CLOBBER
browser/devtools/debugger/DebuggerProcess.jsm
toolkit/components/moz.build
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-More Windows webidl changes
+More Windows webidl changes 
--- 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/base/content/test/social/browser_blocklist.js
+++ b/browser/base/content/test/social/browser_blocklist.js
@@ -129,27 +129,29 @@ var tests = {
     let listener = {
       _window: null,
       onOpenWindow: function(aXULWindow) {
         Services.wm.removeListener(this);
         this._window = aXULWindow;
         let domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIDOMWindow);
 
-        domwindow.addEventListener("unload", function _unload() {
-          domwindow.removeEventListener("unload", _unload, false);
-          windowWasClosed = true;
+        domwindow.addEventListener("load", function _load() {
+          domwindow.removeEventListener("load", _load, false);
+
+          domwindow.addEventListener("unload", function _unload() {
+            domwindow.removeEventListener("unload", _unload, false);
+            info("blocklist window was closed");
+            windowWasClosed = true;
+          }, false);
+
+          is(domwindow.document.location.href, URI_EXTENSION_BLOCKLIST_DIALOG, "dialog opened and focused");
+          domwindow.close();
+
         }, false);
-        info("dialog opened, waiting for focus");
-        waitForFocus(function() {
-          is(domwindow.document.location.href, URI_EXTENSION_BLOCKLIST_DIALOG, "dialog opened and focused");
-          executeSoon(function() {
-            domwindow.close();
-          });
-        }, domwindow);
       },
       onCloseWindow: function(aXULWindow) { },
       onWindowTitleChange: function(aXULWindow, aNewTitle) { }
     };
 
     Services.wm.addListener(listener);
 
     setManifestPref("social.manifest.blocked", manifest_bad);
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -152,18 +152,17 @@ let CustomizableUIInternal = {
       // Windows 8 is version 6.2.
       let version = Cc["@mozilla.org/system-info;1"]
                       .getService(Ci.nsIPropertyBag2)
                       .getProperty("version");
       isMetroCapable = (parseFloat(version) >= 6.2);
     } catch (ex) { }
 
     if (isMetroCapable) {
-      // TODO: Bug 942915 - Place 'Metro Mode' button as a default
-      // for Windows 8 in the customization panel.
+      panelPlacements.push("switch-to-metro-button");
     }
 #endif
 #endif
 
     let showCharacterEncoding = Services.prefs.getComplexValue(
       "browser.menu.showCharacterEncoding",
       Ci.nsIPrefLocalizedString
     ).data;
--- a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
+++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
@@ -23,25 +23,25 @@ let gTests = [
       let item = document.getElementById(kTestWidget1);
       ok(!item, "There should no longer be an item");
     },
   },
   {
     desc: "Creating and destroying a widget should correctly deal with panel placeholders",
     run: function() {
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-      is(panel.querySelectorAll(".panel-customization-placeholder").length, 3, "The number of placeholders should be correct.");
+      is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 2 : 3, "The number of placeholders should be correct.");
       CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
       let elem = document.getElementById(kTestWidget2);
       let wrapper = document.getElementById("wrapper-" + kTestWidget2);
       ok(elem, "There should be an item");
       ok(wrapper, "There should be a wrapper");
       is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
       is(wrapper.parentNode, panel, "Wrapper should be in panel");
-      is(panel.querySelectorAll(".panel-customization-placeholder").length, 2, "The number of placeholders should be correct.");
+      is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct.");
       CustomizableUI.destroyWidget(kTestWidget2);
       wrapper = document.getElementById("wrapper-" + kTestWidget2);
       ok(!wrapper, "There should be a wrapper");
       let item = document.getElementById(kTestWidget2);
       ok(!item, "There should no longer be an item");
     },
     teardown: endCustomizing
   },
--- a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
+++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
@@ -16,16 +16,17 @@ let gTests = [
                                  "save-page-button",
                                  "zoom-controls",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(zoomControls, printButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       let newWindowButton = document.getElementById("new-window-button");
       simulateItemDrag(zoomControls, newWindowButton);
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
@@ -42,16 +43,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(zoomControls, savePageButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(CustomizableUI.inDefaultState, "Should be in default state.");
     },
   },
   {
     desc: "Dragging the zoom controls to be before the new-window " +
           "button should not move any widgets.",
@@ -65,16 +67,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(zoomControls, newWindowButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
     desc: "Dragging the zoom controls to be before the history-panelmenu " +
           "should move the zoom-controls in to the row higher than the " +
@@ -89,16 +92,17 @@ let gTests = [
                                  "save-page-button",
                                  "zoom-controls",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(zoomControls, historyPanelMenu);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       let newWindowButton = document.getElementById("new-window-button");
       simulateItemDrag(zoomControls, newWindowButton);
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
@@ -116,16 +120,17 @@ let gTests = [
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "zoom-controls",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(zoomControls, preferencesButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       let newWindowButton = document.getElementById("new-window-button");
       simulateItemDrag(zoomControls, newWindowButton);
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
@@ -143,16 +148,17 @@ let gTests = [
                                    "zoom-controls",
                                    "save-page-button",
                                    "print-button",
                                    "history-panelmenu",
                                    "fullscreen-button",
                                    "find-button",
                                    "preferences-button",
                                    "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterInsert);
       simulateItemDrag(developerButton, zoomControls);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       let palette = document.getElementById("customization-palette");
       // Check that the palette items are re-wrapped correctly.
       let feedWrapper = document.getElementById("wrapper-feed-button");
       let feedButton = document.getElementById("feed-button");
       is(feedButton.parentNode, feedWrapper,
@@ -181,16 +187,17 @@ let gTests = [
                                    "zoom-controls",
                                    "save-page-button",
                                    "print-button",
                                    "history-panelmenu",
                                    "fullscreen-button",
                                    "find-button",
                                    "preferences-button",
                                    "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterInsert);
       simulateItemDrag(developerButton, editControls);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       let palette = document.getElementById("customization-palette");
       // Check that the palette items are re-wrapped correctly.
       let feedWrapper = document.getElementById("wrapper-feed-button");
       let feedButton = document.getElementById("feed-button");
       is(feedButton.parentNode, feedWrapper,
@@ -216,16 +223,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, zoomControls);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
     desc: "Dragging the edit-controls to be before the new-window-button should " +
           "move the zoom-controls before the edit-controls.",
@@ -239,16 +247,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, newWindowButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(editControls, zoomControls);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
@@ -265,16 +274,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, privateBrowsingButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(editControls, zoomControls);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
@@ -291,16 +301,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, savePageButton);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(editControls, zoomControls);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
@@ -316,16 +327,17 @@ let gTests = [
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button",
                                  "edit-controls"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, panel);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(editControls, zoomControls);
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
   {
@@ -340,16 +352,17 @@ let gTests = [
                                  "privatebrowsing-button",
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       let paletteChildElementCount = palette.childElementCount;
       simulateItemDrag(editControls, palette);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       is(paletteChildElementCount + 1, palette.childElementCount,
          "The palette should have a new child, congratulations!");
       is(editControls.parentNode.id, "wrapper-edit-controls",
          "The edit-controls should be properly wrapped.");
       is(editControls.parentNode.getAttribute("place"), "palette",
@@ -363,31 +376,33 @@ let gTests = [
   },
   {
     desc: "Dragging the edit-controls to each of the panel placeholders " +
           "should append the edit-controls to the bottom of the panel.",
     setup: startCustomizing,
     run: function() {
       let editControls = document.getElementById("edit-controls");
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
-      for (let i = 0; i < 3; i++) {
+      let numPlaceholders = isInWin8() ? 2 : 3;
+      for (let i = 0; i < numPlaceholders; i++) {
         // NB: We can't just iterate over all of the placeholders
         // because each drag-drop action recreates them.
         let placeholder = panel.getElementsByClassName("panel-customization-placeholder")[i];
         let placementsAfterMove = ["zoom-controls",
                                    "new-window-button",
                                    "privatebrowsing-button",
                                    "save-page-button",
                                    "print-button",
                                    "history-panelmenu",
                                    "fullscreen-button",
                                    "find-button",
                                    "preferences-button",
                                    "add-ons-button",
                                    "edit-controls"];
+        addSwitchToMetroButtonInWindows8(placementsAfterMove);
         simulateItemDrag(editControls, placeholder);
         assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
         let zoomControls = document.getElementById("zoom-controls");
         simulateItemDrag(editControls, zoomControls);
         ok(CustomizableUI.inDefaultState, "Should still be in default state.");
       }
     },
   },
@@ -420,21 +435,26 @@ let gTests = [
                                  "save-page-button",
                                  "print-button",
                                  "history-panelmenu",
                                  "fullscreen-button",
                                  "find-button",
                                  "preferences-button",
                                  "add-ons-button",
                                  "edit-controls"];
+      addSwitchToMetroButtonInWindows8(placementsAfterMove);
       simulateItemDrag(editControls, target);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
       let itemToDrag = "sync-button";
       let button = document.getElementById(itemToDrag);
-      placementsAfterMove.push(itemToDrag);
+      if (!isInWin8()) {
+        placementsAfterMove.push(itemToDrag);
+      } else {
+        placementsAfterMove.splice(11, 0, itemToDrag);
+      }
       simulateItemDrag(button, editControls);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
 
       // Put stuff back:
       let palette = document.getElementById("customization-palette");
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(button, palette);
       simulateItemDrag(editControls, zoomControls);
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -6,116 +6,155 @@ let gTests = [
   {
     desc: "One orphaned item should have two placeholders next to it.",
     setup: startCustomizing,
     run: function() {
       let btn = document.getElementById("developer-button");
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
       let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
-      let placementsAfterAppend = placements.concat(["developer-button"]);
-      simulateItemDrag(btn, panel);
-      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
-      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      if (!isInWin8()) {
+        placements = placements.concat(["developer-button"]);
+        simulateItemDrag(btn, panel);
+        ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      } else {
+        ok(CustomizableUI.inDefaultState, "Should be in default state.");
+      }
+
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
       is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
 
       yield endCustomizing();
       yield startCustomizing();
       is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
 
-      let palette = document.getElementById("customization-palette");
-      simulateItemDrag(btn, palette);
+      if (!isInWin8()) {
+        let palette = document.getElementById("customization-palette");
+        simulateItemDrag(btn, palette);
+      }
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
   {
     desc: "Two orphaned items should have one placeholder next to them (case 1).",
     setup: startCustomizing,
     run: function() {
       let btn = document.getElementById("developer-button");
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
       let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
-      let placementsAfterAppend = placements.concat(["developer-button", "sync-button"]);
+      let placementsAfterAppend = placements.concat(["developer-button"]);
       simulateItemDrag(btn, panel);
-      btn = document.getElementById("sync-button");
-      simulateItemDrag(btn, panel);
+
+      if (!isInWin8()) {
+        placementsAfterAppend = placementsAfterAppend.concat(["sync-button"]);
+        btn = document.getElementById("sync-button");
+        simulateItemDrag(btn, panel);
+      }
+
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting");
 
       yield endCustomizing();
       yield startCustomizing();
       is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering");
 
       let palette = document.getElementById("customization-palette");
       simulateItemDrag(btn, palette);
-      btn = document.getElementById("developer-button");
-      simulateItemDrag(btn, palette);
+
+      if (!isInWin8()) {
+        btn = document.getElementById("developer-button");
+        simulateItemDrag(btn, palette);
+      }
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
   {
     desc: "Two orphaned items should have one placeholder next to them (case 2).",
     setup: startCustomizing,
     run: function() {
       let btn = document.getElementById("add-ons-button");
+      let btn2 = document.getElementById("switch-to-metro-button");
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
       let palette = document.getElementById("customization-palette");
       let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
       let placementsAfterAppend = placements.filter(p => p != btn.id);
       simulateItemDrag(btn, palette);
+
+      if (isInWin8()) {
+        placementsAfterAppend = placementsAfterAppend.filter(p => p != btn2.id);
+        simulateItemDrag(btn2, palette);
+      }
+
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting");
 
       yield endCustomizing();
       yield startCustomizing();
       is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering");
 
       simulateItemDrag(btn, panel);
+
+      if (isInWin8()) {
+        simulateItemDrag(btn2, panel);
+      }
+
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
   {
     desc: "A wide widget at the bottom of the panel should have three placeholders after it.",
     setup: startCustomizing,
     run: function() {
       let btn = document.getElementById("edit-controls");
+      let metroBtn = document.getElementById("switch-to-metro-button");
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let palette = document.getElementById("customization-palette");
       let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
 
+      if (isInWin8()) {
+        // Remove switch-to-metro-button
+        placements.pop();
+        simulateItemDrag(metroBtn, palette);
+      }
+
       let placementsAfterAppend = placements.concat([placements.shift()]);
       simulateItemDrag(btn, panel);
       assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
       ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
       is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
 
       yield endCustomizing();
       yield startCustomizing();
       is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
 
+      if (isInWin8()) {
+        simulateItemDrag(metroBtn, panel);
+      }
       let zoomControls = document.getElementById("zoom-controls");
       simulateItemDrag(btn, zoomControls);
       ok(CustomizableUI.inDefaultState, "Should be in default state again.");
     },
   },
   {
-    desc: "The default placements should have three placeholders at the bottom.",
+    desc: "The default placements should have three placeholders at the bottom (or 2 in win8).",
     setup: startCustomizing,
     run: function() {
+      let numPlaceholders = isInWin8() ? 2 : 3;
       let panel = document.getElementById(CustomizableUI.AREA_PANEL);
       ok(CustomizableUI.inDefaultState, "Should be in default state.");
-      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
+      is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
 
       yield endCustomizing();
       yield startCustomizing();
-      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
+      is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering");
 
       ok(CustomizableUI.inDefaultState, "Should still be in default state.");
     },
   },
 ];
 
 function asyncCleanup() {
   yield endCustomizing();
--- a/browser/components/customizableui/test/head.js
+++ b/browser/components/customizableui/test/head.js
@@ -49,16 +49,31 @@ function removeCustomToolbars() {
   }
   gAddedToolbars.clear();
 }
 
 function resetCustomization() {
   return CustomizableUI.reset();
 }
 
+function isInWin8() {
+  let sysInfo = Services.sysinfo;
+  let osName = sysInfo.getProperty("name");
+  let version = sysInfo.getProperty("version");
+
+  // Windows 8 is version >= 6.2
+  return osName == "Windows_NT" && version >= 6.2;
+}
+
+function addSwitchToMetroButtonInWindows8(areaPanelPlacements) {
+  if (isInWin8()) {
+    areaPanelPlacements.push("switch-to-metro-button");
+  }
+}
+
 function assertAreaPlacements(areaId, expectedPlacements) {
   let actualPlacements = getAreaWidgetIds(areaId);
   is(actualPlacements.length, expectedPlacements.length,
      "Area " + areaId + " should have " + expectedPlacements.length + " items.");
   let minItems = Math.min(expectedPlacements.length, actualPlacements.length);
   for (let i = 0; i < minItems; i++) {
     if (typeof expectedPlacements[i] == "string") {
       is(actualPlacements[i], expectedPlacements[i],
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -1449,18 +1449,22 @@ let SessionStoreInternal = {
 
   setBrowserState: function ssi_setBrowserState(aState) {
     this._handleClosedWindows();
 
     try {
       var state = JSON.parse(aState);
     }
     catch (ex) { /* invalid state object - don't restore anything */ }
-    if (!state || !state.windows)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!state) {
+      throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG);
+    }
+    if (!state.windows) {
+      throw Components.Exception("No windows", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     this._browserSetState = true;
 
     // Make sure the priority queue is emptied out
     this._resetRestoringState();
 
     var window = this._getMostRecentBrowserWindow();
     if (!window) {
@@ -1496,77 +1500,83 @@ let SessionStoreInternal = {
       return this._toJSONString(this._getWindowState(aWindow));
     }
 
     if (DyingWindowCache.has(aWindow)) {
       let data = DyingWindowCache.get(aWindow);
       return this._toJSONString({ windows: [data] });
     }
 
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
   },
 
   setWindowState: function ssi_setWindowState(aWindow, aState, aOverwrite) {
-    if (!aWindow.__SSi)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!aWindow.__SSi) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     this.restoreWindow(aWindow, aState, {overwriteTabs: aOverwrite});
   },
 
   getTabState: function ssi_getTabState(aTab) {
-    if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!aTab.ownerDocument) {
+      throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG);
+    }
+    if (!aTab.ownerDocument.defaultView.__SSi) {
+      throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     let tabState = TabState.collectSync(aTab);
 
     return this._toJSONString(tabState);
   },
 
   setTabState: function ssi_setTabState(aTab, aState) {
     // Remove the tab state from the cache.
     // Note that we cannot simply replace the contents of the cache
     // as |aState| can be an incomplete state that will be completed
     // by |restoreTabs|.
     let tabState = JSON.parse(aState);
     if (!tabState) {
-      debug("Empty state argument");
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+      throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG);
     }
     if (typeof tabState != "object") {
-      debug("State argument does not represent an object");
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+      throw Components.Exception("Not an object", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!("entries" in tabState)) {
-      debug("State argument must contain field 'entries'");
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+      throw Components.Exception("Invalid state object: no entries", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!aTab.ownerDocument) {
-      debug("Tab argument must have an owner document");
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+      throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG);
     }
 
     let window = aTab.ownerDocument.defaultView;
     if (!("__SSi" in window)) {
-      debug("Default view of ownerDocument must have a unique identifier");
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
     if (aTab.linkedBrowser.__SS_restoreState) {
       this._resetTabRestoringState(aTab);
     }
 
     TabStateCache.delete(aTab);
     this._setWindowStateBusy(window);
     this.restoreTabs(window, [aTab], [tabState], 0);
   },
 
   duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
-    if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi ||
-        !aWindow.getBrowser)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!aTab.ownerDocument) {
+      throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG);
+    }
+    if (!aTab.ownerDocument.defaultView.__SSi) {
+      throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
+    if (!aWindow.getBrowser) {
+      throw Components.Exception("Invalid window object: no getBrowser", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     // Flush all data queued in the content script because we will need that
     // state to properly duplicate the given tab.
     TabState.flush(aTab.linkedBrowser);
 
     // Duplicate the tab state
     let tabState = TabState.clone(aTab);
 
@@ -1581,78 +1591,81 @@ let SessionStoreInternal = {
 
     this.restoreTabs(aWindow, [newTab], [tabState], 0,
                      true /* Load this tab right away. */);
 
     return newTab;
   },
 
   setNumberOfTabsClosedLast: function ssi_setNumberOfTabsClosedLast(aWindow, aNumber) {
-    if (this._disabledForMultiProcess)
+    if (this._disabledForMultiProcess) {
       return;
-
-    if ("__SSi" in aWindow) {
-      return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber);
     }
 
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!("__SSi" in aWindow)) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
+
+    return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber);
   },
 
   /* Used to undo batch tab-close operations. Defaults to 1. */
   getNumberOfTabsClosedLast: function ssi_getNumberOfTabsClosedLast(aWindow) {
-    if (this._disabledForMultiProcess)
+    if (this._disabledForMultiProcess) {
       return 0;
-
-    if ("__SSi" in aWindow) {
-      // Blank tabs cannot be undo-closed, so the number returned by
-      // the NumberOfTabsClosedLastPerWindow can be greater than the
-      // return value of getClosedTabCount. We won't restore blank
-      // tabs, so we return the minimum of these two values.
-      return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1,
-                      this.getClosedTabCount(aWindow));
+    }
+
+    if (!("__SSi" in aWindow)) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
-
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    // Blank tabs cannot be undo-closed, so the number returned by
+    // the NumberOfTabsClosedLastPerWindow can be greater than the
+    // return value of getClosedTabCount. We won't restore blank
+    // tabs, so we return the minimum of these two values.
+    return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1,
+                    this.getClosedTabCount(aWindow));
   },
 
   getClosedTabCount: function ssi_getClosedTabCount(aWindow) {
     if ("__SSi" in aWindow) {
       return this._windows[aWindow.__SSi]._closedTabs.length;
     }
 
-    if (DyingWindowCache.has(aWindow)) {
-      return DyingWindowCache.get(aWindow)._closedTabs.length;
+    if (!DyingWindowCache.has(aWindow)) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    return DyingWindowCache.get(aWindow)._closedTabs.length;
   },
 
   getClosedTabData: function ssi_getClosedTabDataAt(aWindow) {
     if ("__SSi" in aWindow) {
       return this._toJSONString(this._windows[aWindow.__SSi]._closedTabs);
     }
 
-    if (DyingWindowCache.has(aWindow)) {
-      let data = DyingWindowCache.get(aWindow);
-      return this._toJSONString(data._closedTabs);
+    if (!DyingWindowCache.has(aWindow)) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
 
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    let data = DyingWindowCache.get(aWindow);
+    return this._toJSONString(data._closedTabs);
   },
 
   undoCloseTab: function ssi_undoCloseTab(aWindow, aIndex) {
-    if (!aWindow.__SSi)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!aWindow.__SSi) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     var closedTabs = this._windows[aWindow.__SSi]._closedTabs;
 
     // default to the most-recently closed tab
     aIndex = aIndex || 0;
-    if (!(aIndex in closedTabs))
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!(aIndex in closedTabs)) {
+      throw Components.Exception("Invalid index: not in the closed tabs", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     // fetch the data of closed tab, while removing it from the array
     let closedTab = closedTabs.splice(aIndex, 1).shift();
     let closedTabState = closedTab.state;
 
     this._setWindowStateBusy(aWindow);
     // create a new tab
     let tabbrowser = aWindow.gBrowser;
@@ -1666,87 +1679,90 @@ let SessionStoreInternal = {
 
     // focus the tab's content area (bug 342432)
     tab.linkedBrowser.focus();
 
     return tab;
   },
 
   forgetClosedTab: function ssi_forgetClosedTab(aWindow, aIndex) {
-    if (!aWindow.__SSi)
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!aWindow.__SSi) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     var closedTabs = this._windows[aWindow.__SSi]._closedTabs;
 
     // default to the most-recently closed tab
     aIndex = aIndex || 0;
-    if (!(aIndex in closedTabs))
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!(aIndex in closedTabs)) {
+      throw Components.Exception("Invalid index: not in the closed tabs", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     // remove closed tab from the array
     closedTabs.splice(aIndex, 1);
   },
 
   getClosedWindowCount: function ssi_getClosedWindowCount() {
     return this._closedWindows.length;
   },
 
   getClosedWindowData: function ssi_getClosedWindowData() {
     return this._toJSONString(this._closedWindows);
   },
 
   undoCloseWindow: function ssi_undoCloseWindow(aIndex) {
-    if (!(aIndex in this._closedWindows))
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!(aIndex in this._closedWindows)) {
+      throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     // reopen the window
     let state = { windows: this._closedWindows.splice(aIndex, 1) };
     let window = this._openWindowWithState(state);
     this.windowToFocus = window;
     return window;
   },
 
   forgetClosedWindow: function ssi_forgetClosedWindow(aIndex) {
     // default to the most-recently closed window
     aIndex = aIndex || 0;
-    if (!(aIndex in this._closedWindows))
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!(aIndex in this._closedWindows)) {
+      throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG);
+    }
 
     // remove closed window from the array
     this._closedWindows.splice(aIndex, 1);
   },
 
   getWindowValue: function ssi_getWindowValue(aWindow, aKey) {
-    if (this._disabledForMultiProcess)
+    if (this._disabledForMultiProcess) {
       return "";
+    }
 
     if ("__SSi" in aWindow) {
       var data = this._windows[aWindow.__SSi].extData || {};
       return data[aKey] || "";
     }
 
     if (DyingWindowCache.has(aWindow)) {
       let data = DyingWindowCache.get(aWindow).extData || {};
       return data[aKey] || "";
     }
 
-    throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
   },
 
   setWindowValue: function ssi_setWindowValue(aWindow, aKey, aStringValue) {
-    if (aWindow.__SSi) {
-      if (!this._windows[aWindow.__SSi].extData) {
-        this._windows[aWindow.__SSi].extData = {};
-      }
-      this._windows[aWindow.__SSi].extData[aKey] = aStringValue;
-      this.saveStateDelayed(aWindow);
+    if (!("__SSi" in aWindow)) {
+      throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
-    else {
-      throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
+    if (!this._windows[aWindow.__SSi].extData) {
+      this._windows[aWindow.__SSi].extData = {};
     }
+    this._windows[aWindow.__SSi].extData[aKey] = aStringValue;
+    this.saveStateDelayed(aWindow);
   },
 
   deleteWindowValue: function ssi_deleteWindowValue(aWindow, aKey) {
     if (aWindow.__SSi && this._windows[aWindow.__SSi].extData &&
         this._windows[aWindow.__SSi].extData[aKey])
       delete this._windows[aWindow.__SSi].extData[aKey];
     this.saveStateDelayed(aWindow);
   },
@@ -1835,31 +1851,33 @@ let SessionStoreInternal = {
    * Restores the session state stored in LastSession. This will attempt
    * to merge data into the current session. If a window was opened at startup
    * with pinned tab(s), then the remaining data from the previous session for
    * that window will be opened into that winddow. Otherwise new windows will
    * be opened.
    */
   restoreLastSession: function ssi_restoreLastSession() {
     // Use the public getter since it also checks PB mode
-    if (!this.canRestoreLastSession)
-      throw (Components.returnCode = Cr.NS_ERROR_FAILURE);
+    if (!this.canRestoreLastSession) {
+      throw Components.Exception("Last session can not be restored");
+    }
 
     // First collect each window with its id...
     let windows = {};
     this._forEachBrowserWindow(function(aWindow) {
       if (aWindow.__SS_lastSessionWindowID)
         windows[aWindow.__SS_lastSessionWindowID] = aWindow;
     });
 
     let lastSessionState = LastSession.getState();
 
     // This shouldn't ever be the case...
-    if (!lastSessionState.windows.length)
-      throw (Components.returnCode = Cr.NS_ERROR_UNEXPECTED);
+    if (!lastSessionState.windows.length) {
+      throw Components.Exception("lastSessionState has no windows", Cr.NS_ERROR_UNEXPECTED);
+    }
 
     // We're technically doing a restore, so set things up so we send the
     // notification when we're done. We want to send "sessionstore-browser-state-restored".
     this._restoreCount = lastSessionState.windows.length;
     this._browserSetState = true;
 
     // We want to re-use the last opened window instead of opening a new one in
     // the case where it's "empty" and not associated with a window in the session.
--- 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/browser_dbg_globalactor.js
+++ b/browser/devtools/debugger/test/browser_dbg_globalactor.js
@@ -39,35 +39,24 @@ function test() {
 
           // Make sure that lazily-created actors are created only once.
           let conn = transport._serverConnection;
 
           // First we look for the pool of global actors.
           let extraPools = conn._extraPools;
           let globalPool;
 
+          let actorPrefix = conn._prefix + "test_one";
+          let count = 0;
           for (let pool of extraPools) {
-            if (Object.keys(pool._actors).some(e => {
-              // Tab actors are in the global pool.
-              let re = new RegExp(conn._prefix + "tab", "g");
-              return e.match(re) !== null;
-            })) {
-              globalPool = pool;
-              break;
-            }
+            count += Object.keys(pool._actors).filter(e => {
+              return e.startsWith(actorPrefix);
+            }).length;
           }
-
-          // Then we look if the global pool contains only one test actor.
-          let actorPrefix = conn._prefix + "test_one";
-          let actors = Object.keys(globalPool._actors).join();
-          info("Global actors: " + actors);
-
-          isnot(actors.indexOf(actorPrefix), -1,
-            "The test actor exists in the pool.");
-          is(actors.indexOf(actorPrefix), actors.lastIndexOf(actorPrefix),
-            "Only one actor exists in the pool.");
+          is(count, 2,
+            "Only two actor exists in all pools. One tab actor and one global.");
 
           gClient.close(finish);
         });
       });
     });
   });
 }
--- 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/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -50,27 +50,40 @@ const EVENTS = {
   STARTED_RECEIVING_RESPONSE: "NetMonitor:NetworkEventUpdating:ResponseStart",
   UPDATING_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdating:ResponseContent",
   RECEIVED_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdated:ResponseContent",
 
   // When the request post params are displayed in the UI.
   REQUEST_POST_PARAMS_DISPLAYED: "NetMonitor:RequestPostParamsAvailable",
 
   // When the response body is displayed in the UI.
-  RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable"
-}
+  RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable",
+
+  // When `onTabSelect` is fired and subsequently rendered
+  TAB_UPDATED: "NetMonitor:TabUpdated",
+
+  // Fired when Sidebar is finished being populated
+  SIDEBAR_POPULATED: "NetMonitor:SidebarPopulated",
+
+  // Fired when NetworkDetailsView is finished being populated
+  NETWORKDETAILSVIEW_POPULATED: "NetMonitor:NetworkDetailsViewPopulated",
+
+  // Fired when NetworkDetailsView is finished being populated
+  CUSTOMREQUESTVIEW_POPULATED: "NetMonitor:CustomRequestViewPopulated"
+};
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
+Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource:///modules/devtools/shared/event-emitter.js");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
+const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const Editor = require("devtools/sourceeditor/editor");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
--- a/browser/devtools/netmonitor/netmonitor-panel.js
+++ b/browser/devtools/netmonitor/netmonitor-panel.js
@@ -1,17 +1,17 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 { Cc, Ci, Cu, Cr } = require("chrome");
-const promise = require("sdk/core/promise");
+const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 const EventEmitter = require("devtools/shared/event-emitter");
 
 function NetMonitorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   this._view = this.panelWin.NetMonitorView;
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -1377,25 +1377,29 @@ SidebarView.prototype = {
     NetMonitorView.RequestsMenu._flushWaterfallViews(true);
   },
 
   /**
    * Populates this view with the specified data.
    *
    * @param object aData
    *        The data source (this should be the attachment of a request item).
+   * @return object
+   *        Returns a promise that resolves upon population of the subview.
    */
   populate: function(aData) {
-    if (aData.isCustom) {
-      NetMonitorView.CustomRequest.populate(aData);
-      $("#details-pane").selectedIndex = 0;
-    } else {
-      NetMonitorView.NetworkDetails.populate(aData);
-      $("#details-pane").selectedIndex = 1;
-    }
+    let isCustom = aData.isCustom;
+    let view = isCustom ?
+      NetMonitorView.CustomRequest :
+      NetMonitorView.NetworkDetails;
+
+    return view.populate(aData).then(() => {
+      $("#details-pane").selectedIndex = isCustom ? 0 : 1
+      window.emit(EVENTS.SIDEBAR_POPULATED)
+    });
   },
 
   /**
    * Hides this container.
    */
   reset: function() {
     this.toggle(false);
   }
@@ -1409,32 +1413,41 @@ function CustomRequestView() {
 }
 
 CustomRequestView.prototype = {
   /**
    * Populates this view with the specified data.
    *
    * @param object aData
    *        The data source (this should be the attachment of a request item).
+   * @return object
+   *        Returns a promise that resolves upon population the view.
    */
   populate: function(aData) {
     $("#custom-url-value").value = aData.url;
     $("#custom-method-value").value = aData.method;
     $("#custom-headers-value").value =
        writeHeaderText(aData.requestHeaders.headers);
 
+    let view = this;
+    let postDataPromise = null;
+
     if (aData.requestPostData) {
       let body = aData.requestPostData.postData.text;
 
-      gNetwork.getString(body).then(aString => {
+      postDataPromise = gNetwork.getString(body).then(aString => {
         $("#custom-postdata-value").value =  aString;
       });
+    } else {
+      postDataPromise = promise.resolve();
     }
 
-    this.updateCustomQuery(aData.url);
+    return postDataPromise
+      .then(() => view.updateCustomQuery(aData.url))
+      .then(() => window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED));
   },
 
   /**
    * Handle user input in the custom request form.
    *
    * @param object aField
    *        the field that the user updated.
    */
@@ -1579,16 +1592,18 @@ NetworkDetailsView.prototype = {
     this._dataSrc = null;
   },
 
   /**
    * Populates this view with the specified data.
    *
    * @param object aData
    *        The data source (this should be the attachment of a request item).
+   * @return object
+   *        Returns a promise that resolves upon population the view.
    */
   populate: function(aData) {
     $("#request-params-box").setAttribute("flex", "1");
     $("#request-params-box").hidden = false;
     $("#request-post-data-textarea-box").hidden = true;
     $("#response-content-info-header").hidden = true;
     $("#response-content-json-box").hidden = true;
     $("#response-content-textarea-box").hidden = true;
@@ -1596,53 +1611,59 @@ NetworkDetailsView.prototype = {
 
     this._headers.empty();
     this._cookies.empty();
     this._params.empty();
     this._json.empty();
 
     this._dataSrc = { src: aData, populated: [] };
     this._onTabSelect();
+    window.emit(EVENTS.NETWORKDETAILSVIEW_POPULATED);
+
+    return promise.resolve();
   },
 
   /**
    * Listener handling the tab selection event.
    */
   _onTabSelect: function() {
     let { src, populated } = this._dataSrc || {};
     let tab = this.widget.selectedIndex;
+    let view = this;
 
     // Make sure the data source is valid and don't populate the same tab twice.
     if (!src || populated[tab]) {
       return;
     }
 
-    switch (tab) {
-      case 0: // "Headers"
-        this._setSummary(src);
-        this._setResponseHeaders(src.responseHeaders);
-        this._setRequestHeaders(src.requestHeaders);
-        break;
-      case 1: // "Cookies"
-        this._setResponseCookies(src.responseCookies);
-        this._setRequestCookies(src.requestCookies);
-        break;
-      case 2: // "Params"
-        this._setRequestGetParams(src.url);
-        this._setRequestPostParams(src.requestHeaders, src.requestPostData);
-        break;
-      case 3: // "Response"
-        this._setResponseBody(src.url, src.responseContent);
-        break;
-      case 4: // "Timings"
-        this._setTimingsInformation(src.eventTimings);
-        break;
-    }
-
-    populated[tab] = true;
+    Task.spawn(function*() {
+      switch (tab) {
+        case 0: // "Headers"
+          yield view._setSummary(src);
+          yield view._setResponseHeaders(src.responseHeaders);
+          yield view._setRequestHeaders(src.requestHeaders);
+          break;
+        case 1: // "Cookies"
+          yield view._setResponseCookies(src.responseCookies);
+          yield view._setRequestCookies(src.requestCookies);
+          break;
+        case 2: // "Params"
+          yield view._setRequestGetParams(src.url);
+          yield view._setRequestPostParams(src.requestHeaders, src.requestPostData);
+          break;
+        case 3: // "Response"
+          yield view._setResponseBody(src.url, src.responseContent);
+          break;
+        case 4: // "Timings"
+          yield view._setTimingsInformation(src.eventTimings);
+          break;
+      }
+      populated[tab] = true;
+      window.emit(EVENTS.TAB_UPDATED);
+    });
   },
 
   /**
    * Sets the network request summary shown in this view.
    *
    * @param object aData
    *        The data source (this should be the attachment of a request item).
    */
@@ -1679,116 +1700,135 @@ NetworkDetailsView.prototype = {
     }
   },
 
   /**
    * Sets the network request headers shown in this view.
    *
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that resolves when request headers are set.
    */
   _setRequestHeaders: function(aResponse) {
     if (aResponse && aResponse.headers.length) {
-      this._addHeaders(this._requestHeaders, aResponse);
+      return this._addHeaders(this._requestHeaders, aResponse);
     }
+    return promise.resolve();
   },
 
   /**
    * Sets the network response headers shown in this view.
    *
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that resolves when response headers are set.
    */
   _setResponseHeaders: function(aResponse) {
     if (aResponse && aResponse.headers.length) {
       aResponse.headers.sort((a, b) => a.name > b.name);
-      this._addHeaders(this._responseHeaders, aResponse);
+      return this._addHeaders(this._responseHeaders, aResponse);
     }
+    return promise.resolve();
   },
 
   /**
    * Populates the headers container in this view with the specified data.
    *
    * @param string aName
    *        The type of headers to populate (request or response).
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that resolves when headers are added.
    */
   _addHeaders: function(aName, aResponse) {
     let kb = aResponse.headersSize / 1024;
     let size = L10N.numberWithDecimals(kb, HEADERS_SIZE_DECIMALS);
     let text = L10N.getFormatStr("networkMenu.sizeKB", size);
     let headersScope = this._headers.addScope(aName + " (" + text + ")");
     headersScope.expanded = true;
 
-    for (let header of aResponse.headers) {
+    return promise.all(aResponse.headers.map(header => {
       let headerVar = headersScope.addItem(header.name, {}, true);
-      gNetwork.getString(header.value).then(aString => headerVar.setGrip(aString));
-    }
+      return gNetwork.getString(header.value)
+             .then(aString => headerVar.setGrip(aString));
+    }));
   },
 
   /**
    * Sets the network request cookies shown in this view.
    *
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that is resolved when the request cookies are set.
    */
   _setRequestCookies: function(aResponse) {
     if (aResponse && aResponse.cookies.length) {
       aResponse.cookies.sort((a, b) => a.name > b.name);
-      this._addCookies(this._requestCookies, aResponse);
+      return this._addCookies(this._requestCookies, aResponse);
     }
+    return promise.resolve();
   },
 
   /**
    * Sets the network response cookies shown in this view.
    *
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that is resolved when the response cookies are set.
    */
   _setResponseCookies: function(aResponse) {
     if (aResponse && aResponse.cookies.length) {
-      this._addCookies(this._responseCookies, aResponse);
+      return this._addCookies(this._responseCookies, aResponse);
     }
+    return promise.resolve();
   },
 
   /**
    * Populates the cookies container in this view with the specified data.
    *
    * @param string aName
    *        The type of cookies to populate (request or response).
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        Returns a promise that resolves upon the adding of cookies.
    */
   _addCookies: function(aName, aResponse) {
     let cookiesScope = this._cookies.addScope(aName);
     cookiesScope.expanded = true;
 
-    for (let cookie of aResponse.cookies) {
+    return promise.all(aResponse.cookies.map(cookie => {
       let cookieVar = cookiesScope.addItem(cookie.name, {}, true);
-      gNetwork.getString(cookie.value).then(aString => cookieVar.setGrip(aString));
+      return gNetwork.getString(cookie.value).then(aString => {
+        cookieVar.setGrip(aString);
 
-      // By default the cookie name and value are shown. If this is the only
-      // information available, then nothing else is to be displayed.
-      let cookieProps = Object.keys(cookie);
-      if (cookieProps.length == 2) {
-        continue;
-      }
+        // By default the cookie name and value are shown. If this is the only
+        // information available, then nothing else is to be displayed.
+        let cookieProps = Object.keys(cookie);
+        if (cookieProps.length == 2) {
+          return;
+        }
 
-      // Display any other information other than the cookie name and value
-      // which may be available.
-      let rawObject = Object.create(null);
-      let otherProps = cookieProps.filter(e => e != "name" && e != "value");
-      for (let prop of otherProps) {
-        rawObject[prop] = cookie[prop];
-      }
-      cookieVar.populate(rawObject);
-      cookieVar.twisty = true;
-      cookieVar.expanded = true;
-    }
+        // Display any other information other than the cookie name and value
+        // which may be available.
+        let rawObject = Object.create(null);
+        let otherProps = cookieProps.filter(e => e != "name" && e != "value");
+        for (let prop of otherProps) {
+          rawObject[prop] = cookie[prop];
+        }
+        cookieVar.populate(rawObject);
+        cookieVar.twisty = true;
+        cookieVar.expanded = true;
+      });
+    }));
   },
 
   /**
    * Sets the network request get params shown in this view.
    *
    * @param string aUrl
    *        The request's url.
    */
@@ -1801,22 +1841,24 @@ NetworkDetailsView.prototype = {
 
   /**
    * Sets the network request post params shown in this view.
    *
    * @param object aHeadersResponse
    *        The "requestHeaders" message received from the server.
    * @param object aPostDataResponse
    *        The "requestPostData" message received from the server.
+   * @return object
+   *        A promise that is resolved when the request post params are set.
    */
   _setRequestPostParams: function(aHeadersResponse, aPostDataResponse) {
     if (!aHeadersResponse || !aPostDataResponse) {
-      return;
+      return promise.resolve();
     }
-    gNetwork.getString(aPostDataResponse.postData.text).then(aString => {
+    return gNetwork.getString(aPostDataResponse.postData.text).then(aString => {
       // Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42").
       let cType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0];
       let cString = cType ? cType.value : "";
       if (cString.contains("x-www-form-urlencoded") ||
           aString.contains("x-www-form-urlencoded")) {
         let formDataGroups = aString.split(/\r\n|\n|\r/);
         for (let group of formDataGroups) {
           this._addParams(this._paramsFormData, group);
@@ -1828,22 +1870,21 @@ NetworkDetailsView.prototype = {
         // scope in the params view and place the source editor containing
         // the raw post data directly underneath.
         $("#request-params-box").removeAttribute("flex");
         let paramsScope = this._params.addScope(this._paramsPostPayload);
         paramsScope.expanded = true;
         paramsScope.locked = true;
 
         $("#request-post-data-textarea-box").hidden = false;
-        NetMonitorView.editor("#request-post-data-textarea").then(aEditor => {
+        return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => {
           aEditor.setText(aString);
         });
       }
-      window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
-    });
+    }).then(() => window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED));
   },
 
   /**
    * Populates the params container in this view with the specified data.
    *
    * @param string aName
    *        The type of params to populate (get or post).
    * @param string aQueryString
@@ -1865,24 +1906,26 @@ NetworkDetailsView.prototype = {
 
   /**
    * Sets the network response body shown in this view.
    *
    * @param string aUrl
    *        The request's url.
    * @param object aResponse
    *        The message received from the server.
+   * @return object
+   *        A promise that is resolved when the response body is set
    */
   _setResponseBody: function(aUrl, aResponse) {
     if (!aResponse) {
-      return;
+      return promise.resolve();
     }
     let { mimeType, text, encoding } = aResponse.content;
 
-    gNetwork.getString(text).then(aString => {
+    return gNetwork.getString(text).then(aString => {
       // Handle json, which we tentatively identify by checking the MIME type
       // for "json" after any word boundary. This works for the standard
       // "application/json", and also for custom types like "x-bigcorp-json".
       // This should be marginally more reliable than just looking for "json".
       if (/\bjson/.test(mimeType)) {
         let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback.
         let sanitizedJSON = aString.replace(jsonpRegex, "");
         let callbackPadding = aString.match(jsonpRegex);
@@ -1898,32 +1941,32 @@ NetworkDetailsView.prototype = {
 
         // Valid JSON.
         if (jsonObject) {
           $("#response-content-json-box").hidden = false;
           let jsonScopeName = callbackPadding
             ? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
             : L10N.getStr("jsonScopeName");
 
-          this._json.controller.setSingleVariable({
+          return this._json.controller.setSingleVariable({
             label: jsonScopeName,
             rawObject: jsonObject,
-          });
+          }).expanded;
         }
         // Malformed JSON.
         else {
           $("#response-content-textarea-box").hidden = false;
-          NetMonitorView.editor("#response-content-textarea").then(aEditor => {
-            aEditor.setMode(Editor.modes.js);
-            aEditor.setText(aString);
-          });
           let infoHeader = $("#response-content-info-header");
           infoHeader.setAttribute("value", parsingError);
           infoHeader.setAttribute("tooltiptext", parsingError);
           infoHeader.hidden = false;
+          return NetMonitorView.editor("#response-content-textarea").then(aEditor => {
+            aEditor.setMode(Editor.modes.js);
+            aEditor.setText(aString);
+          });
         }
       }
       // Handle images.
       else if (mimeType.contains("image/")) {
         $("#response-content-image-box").setAttribute("align", "center");
         $("#response-content-image-box").setAttribute("pack", "center");
         $("#response-content-image-box").hidden = false;
         $("#response-content-image").src =
@@ -1943,34 +1986,33 @@ NetworkDetailsView.prototype = {
           let { width, height } = e.target.getBoundingClientRect();
           let dimensions = (width - 2) + " x " + (height - 2);
           $("#response-content-image-dimensions-value").setAttribute("value", dimensions);
         };
       }
       // Handle anything else.
       else {
         $("#response-content-textarea-box").hidden = false;
-        NetMonitorView.editor("#response-content-textarea").then(aEditor => {
+        return NetMonitorView.editor("#response-content-textarea").then(aEditor => {
           aEditor.setMode(Editor.modes.text);
           aEditor.setText(aString);
 
           // Maybe set a more appropriate mode in the Source Editor if possible,
           // but avoid doing this for very large files.
           if (aString.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) {
             for (let key in CONTENT_MIME_TYPE_MAPPINGS) {
               if (mimeType.contains(key)) {
                 aEditor.setMode(CONTENT_MIME_TYPE_MAPPINGS[key]);
                 break;
               }
             }
           }
         });
       }
-      window.emit(EVENTS.RESPONSE_BODY_DISPLAYED);
-    });
+    }).then(() => window.emit(EVENTS.RESPONSE_BODY_DISPLAYED));
   },
 
   /**
    * Sets the timings information shown in this view.
    *
    * @param object aResponse
    *        The message received from the server.
    */
--- a/browser/devtools/netmonitor/test/browser_net_content-type.js
+++ b/browser/devtools/netmonitor/test/browser_net_content-type.js
@@ -70,41 +70,37 @@ function test() {
           time: true
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      testResponseTab("xml")
-        .then(() => {
-          RequestsMenu.selectedIndex = 1;
-          return testResponseTab("css");
-        })
-        .then(() => {
-          RequestsMenu.selectedIndex = 2;
-          return testResponseTab("js");
-        })
-        .then(() => {
-          RequestsMenu.selectedIndex = 3;
-          return testResponseTab("json");
-        })
-        .then(() => {
-          RequestsMenu.selectedIndex = 4;
-          return testResponseTab("html");
-        })
-        .then(() => {
-          RequestsMenu.selectedIndex = 5;
-          return testResponseTab("png");
-        })
-        .then(() => {
-          return teardown(aMonitor);
-        })
-        .then(finish);
+      Task.spawn(function*() {
+        yield waitForResponseBodyDisplayed();
+        yield testResponseTab("xml");
+        RequestsMenu.selectedIndex = 1;
+        yield waitForTabUpdated();
+        yield testResponseTab("css");
+        RequestsMenu.selectedIndex = 2;
+        yield waitForTabUpdated();
+        yield testResponseTab("js");
+        RequestsMenu.selectedIndex = 3;
+        yield waitForTabUpdated();
+        yield testResponseTab("json");
+        RequestsMenu.selectedIndex = 4;
+        yield waitForTabUpdated();
+        yield testResponseTab("html");
+        RequestsMenu.selectedIndex = 5;
+        yield waitForTabUpdated();
+        yield testResponseTab("png");
+        yield teardown(aMonitor);
+        finish();
+      });
 
       function testResponseTab(aType) {
         let tab = document.querySelectorAll("#details-pane tab")[3];
         let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
 
         is(tab.getAttribute("selected"), "true",
           "The response tab in the network details pane should be selected.");
 
@@ -216,13 +212,21 @@ function test() {
 
               deferred.resolve();
             });
 
             return deferred.promise;
           }
         }
       }
+
+      function waitForTabUpdated () {
+        return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED);
+      }
+
+      function waitForResponseBodyDisplayed () {
+        return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED);
+      }
     });
 
     aDebuggee.performRequests();
   });
 }
--- a/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js
+++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js
@@ -21,17 +21,20 @@ function test() {
           statusText: "DA DA DA"
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+      let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
+      waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() =>
+        NetMonitorView.editor("#response-content-textarea")
+      ).then((aEditor) => {
         is(aEditor.getText().indexOf("\u044F"), 26, // я
           "The text shown in the source editor is incorrect.");
         is(aEditor.getMode(), Editor.modes.text,
           "The mode active in the source editor is incorrect.");
 
         teardown(aMonitor).then(finish);
       });
     });
--- a/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js
@@ -22,17 +22,20 @@ function test() {
           statusText: "OK"
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+      let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
+      waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() =>
+        NetMonitorView.editor("#response-content-textarea")
+      ).then((aEditor) => {
         is(aEditor.getText().indexOf("\u044F"), 302, // я
           "The text shown in the source editor is incorrect.");
         is(aEditor.getMode(), Editor.modes.html,
           "The mode active in the source editor is incorrect.");
 
         teardown(aMonitor).then(finish);
       });
     });
--- a/browser/devtools/netmonitor/test/browser_net_json-malformed.js
+++ b/browser/devtools/netmonitor/test/browser_net_json-malformed.js
@@ -26,46 +26,49 @@ function test() {
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
       let tab = document.querySelectorAll("#details-pane tab")[3];
       let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
 
-      is(tab.getAttribute("selected"), "true",
-        "The response tab in the network details pane should be selected.");
+      let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
+      waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => {
+        is(tab.getAttribute("selected"), "true",
+          "The response tab in the network details pane should be selected.");
 
-      is(tabpanel.querySelector("#response-content-info-header")
-        .hasAttribute("hidden"), false,
-        "The response info header doesn't have the intended visibility.");
-      is(tabpanel.querySelector("#response-content-info-header")
-        .getAttribute("value"),
-        "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
-        "The response info header doesn't have the intended value attribute.");
-      is(tabpanel.querySelector("#response-content-info-header")
-        .getAttribute("tooltiptext"),
-        "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
-        "The response info header doesn't have the intended tooltiptext attribute.");
+        is(tabpanel.querySelector("#response-content-info-header")
+          .hasAttribute("hidden"), false,
+          "The response info header doesn't have the intended visibility.");
+        is(tabpanel.querySelector("#response-content-info-header")
+          .getAttribute("value"),
+          "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
+          "The response info header doesn't have the intended value attribute.");
+        is(tabpanel.querySelector("#response-content-info-header")
+          .getAttribute("tooltiptext"),
+          "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
+          "The response info header doesn't have the intended tooltiptext attribute.");
 
-      is(tabpanel.querySelector("#response-content-json-box")
-        .hasAttribute("hidden"), true,
-        "The response content json box doesn't have the intended visibility.");
-      is(tabpanel.querySelector("#response-content-textarea-box")
-        .hasAttribute("hidden"), false,
-        "The response content textarea box doesn't have the intended visibility.");
-      is(tabpanel.querySelector("#response-content-image-box")
-        .hasAttribute("hidden"), true,
-        "The response content image box doesn't have the intended visibility.");
+        is(tabpanel.querySelector("#response-content-json-box")
+          .hasAttribute("hidden"), true,
+          "The response content json box doesn't have the intended visibility.");
+        is(tabpanel.querySelector("#response-content-textarea-box")
+          .hasAttribute("hidden"), false,
+          "The response content textarea box doesn't have the intended visibility.");
+        is(tabpanel.querySelector("#response-content-image-box")
+          .hasAttribute("hidden"), true,
+          "The response content image box doesn't have the intended visibility.");
 
-      NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
-        is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },",
-          "The text shown in the source editor is incorrect.");
-        is(aEditor.getMode(), Editor.modes.js,
-          "The mode active in the source editor is incorrect.");
+        NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+          is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },",
+            "The text shown in the source editor is incorrect.");
+          is(aEditor.getMode(), Editor.modes.js,
+            "The mode active in the source editor is incorrect.");
 
-        teardown(aMonitor).then(finish);
+          teardown(aMonitor).then(finish);
+        });
       });
     });
 
     aDebuggee.performRequests();
   });
 }
--- a/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js
+++ b/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js
@@ -25,18 +25,21 @@ function test() {
           time: true
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      testResponseTab();
-      teardown(aMonitor).then(finish);
+      let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
+      waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED)
+        .then(testResponseTab)
+        .then(() => teardown(aMonitor))
+        .then(finish);
 
       function testResponseTab() {
         let tab = document.querySelectorAll("#details-pane tab")[3];
         let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
 
         is(tab.getAttribute("selected"), "true",
           "The response tab in the network details pane should be selected.");
 
--- a/browser/devtools/netmonitor/test/browser_net_jsonp.js
+++ b/browser/devtools/netmonitor/test/browser_net_jsonp.js
@@ -25,18 +25,21 @@ function test() {
           time: true
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      testResponseTab();
-      teardown(aMonitor).then(finish);
+      let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED;
+      waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED)
+        .then(testResponseTab)
+        .then(() => teardown(aMonitor))
+        .then(finish);
 
       function testResponseTab() {
         let tab = document.querySelectorAll("#details-pane tab")[3];
         let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
 
         is(tab.getAttribute("selected"), "true",
           "The response tab in the network details pane should be selected.");
 
--- a/browser/devtools/netmonitor/test/browser_net_post-data-01.js
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-01.js
@@ -35,24 +35,24 @@ function test() {
           time: true
         });
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.getElementById("details-pane-toggle"));
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[2]);
 
-      testParamsTab("urlencoded")
-        .then(() => {
-          RequestsMenu.selectedIndex = 1;
-          return testParamsTab("multipart");
-        })
-        .then(() => {
-          return teardown(aMonitor);
-        })
+      let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED;
+      waitFor(aMonitor.panelWin, TAB_UPDATED).then(() =>
+        testParamsTab("urlencoded")
+      ).then(() => {
+        RequestsMenu.selectedIndex = 1;
+        return waitFor(aMonitor.panelWin, TAB_UPDATED);
+      }).then(() => testParamsTab("multipart"))
+        .then(() => teardown(aMonitor))
         .then(finish);
 
       function testParamsTab(aType) {
         let tab = document.querySelectorAll("#details-pane tab")[2];
         let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
 
         is(tab.getAttribute("selected"), "true",
           "The params tab in the network details pane should be selected.");
--- a/browser/devtools/netmonitor/test/browser_net_post-data-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_post-data-02.js
@@ -15,48 +15,50 @@ function test() {
 
     RequestsMenu.lazyUpdate = false;
     NetworkDetails._params.lazyEmpty = false;
 
     waitForNetworkEvents(aMonitor, 0, 1).then(() => {
       NetMonitorView.toggleDetailsPane({ visible: true }, 2)
       RequestsMenu.selectedIndex = 0;
 
-      let tab = document.querySelectorAll("#event-details-pane tab")[2];
-      let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2];
-
-      is(tab.getAttribute("selected"), "true",
-        "The params tab in the network details pane should be selected.");
+      let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED;
+      waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => {
+        let tab = document.querySelectorAll("#event-details-pane tab")[2];
+        let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2];
 
-      is(tabpanel.querySelector("#request-params-box")
-        .hasAttribute("hidden"), false,
-        "The request params box doesn't have the indended visibility.");
-      is(tabpanel.querySelector("#request-post-data-textarea-box")
-        .hasAttribute("hidden"), true,
-        "The request post data textarea box doesn't have the indended visibility.");
+        is(tab.getAttribute("selected"), "true",
+          "The params tab in the network details pane should be selected.");
 
-      is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
-        "There should be 1 param scopes displayed in this tabpanel.");
-      is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
-        "The empty notice should not be displayed in this tabpanel.");
+        is(tabpanel.querySelector("#request-params-box")
+          .hasAttribute("hidden"), false,
+          "The request params box doesn't have the indended visibility.");
+        is(tabpanel.querySelector("#request-post-data-textarea-box")
+          .hasAttribute("hidden"), true,
+          "The request post data textarea box doesn't have the indended visibility.");
 
-      let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
-      is(postScope.querySelector(".name").getAttribute("value"),
-        L10N.getStr("paramsFormData"),
-        "The post scope doesn't have the correct title.");
+        is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
+          "There should be 1 param scopes displayed in this tabpanel.");
+        is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
+          "The empty notice should not be displayed in this tabpanel.");
+
+        let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
+        is(postScope.querySelector(".name").getAttribute("value"),
+          L10N.getStr("paramsFormData"),
+          "The post scope doesn't have the correct title.");
 
-      is(postScope.querySelectorAll(".variables-view-variable").length, 2,
-        "There should be 2 param values displayed in the post scope.");
-      is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
-        "foo", "The first query param name was incorrect.");
-      is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
-        "\"bar\"", "The first query param value was incorrect.");
-      is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
-        "baz", "The second query param name was incorrect.");
-      is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
-        "\"123\"", "The second query param value was incorrect.");
-
-      teardown(aMonitor).then(finish);
+        is(postScope.querySelectorAll(".variables-view-variable").length, 2,
+          "There should be 2 param values displayed in the post scope.");
+        is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
+          "foo", "The first query param name was incorrect.");
+        is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
+          "\"bar\"", "The first query param value was incorrect.");
+        is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
+          "baz", "The second query param name was incorrect.");
+        is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
+          "\"123\"", "The second query param value was incorrect.");
+        teardown(aMonitor).then(finish);
+      });
     });
 
     aDebuggee.performRequests();
   });
 }
--- a/browser/devtools/netmonitor/test/browser_net_resend.js
+++ b/browser/devtools/netmonitor/test/browser_net_resend.js
@@ -16,41 +16,47 @@ function test() {
   initNetMonitor(POST_DATA_URL).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
     gPanelWin = aMonitor.panelWin;
     gPanelDoc = gPanelWin.document;
 
     let { NetMonitorView } = gPanelWin;
     let { RequestsMenu } = NetMonitorView;
+    let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED;
+    let CUSTOMREQUESTVIEW_POPULATED = aMonitor.panelWin.EVENTS.CUSTOMREQUESTVIEW_POPULATED;
 
     RequestsMenu.lazyUpdate = false;
 
     waitForNetworkEvents(aMonitor, 0, 2).then(() => {
       let origItem = RequestsMenu.getItemAtIndex(0);
       RequestsMenu.selectedItem = origItem;
 
-      // add a new custom request cloned from selected request
-      RequestsMenu.cloneSelectedRequest();
-      testCustomForm(origItem.attachment);
+      waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => {
+        // add a new custom request cloned from selected request
+        RequestsMenu.cloneSelectedRequest();
+        return waitFor(aMonitor.panelWin, CUSTOMREQUESTVIEW_POPULATED);
+      }).then(() => {
+        testCustomForm(origItem.attachment);
 
-      let customItem = RequestsMenu.selectedItem;
-      testCustomItem(customItem, origItem);
+        let customItem = RequestsMenu.selectedItem;
+        testCustomItem(customItem, origItem);
 
-      // edit the custom request
-      editCustomForm(() => {
-        testCustomItemChanged(customItem, origItem);
+        // edit the custom request
+        editCustomForm(() => {
+          testCustomItemChanged(customItem, origItem);
 
-        waitForNetworkEvents(aMonitor, 0, 1).then(() => {
-          let sentItem = RequestsMenu.selectedItem;
-          testSentRequest(sentItem.attachment, origItem.attachment);
-          finishUp(aMonitor);
+          waitForNetworkEvents(aMonitor, 0, 1).then(() => {
+            let sentItem = RequestsMenu.selectedItem;
+            testSentRequest(sentItem.attachment, origItem.attachment);
+            finishUp(aMonitor);
+          });
+          // send the new request
+          RequestsMenu.sendCustomRequest();
         });
-        // send the new request
-        RequestsMenu.sendCustomRequest();
       });
     });
 
     aDebuggee.performRequests();
   });
 }
 
 function testCustomItem(aItem, aOrigItem) {
--- a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
+++ b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js
@@ -6,20 +6,21 @@
  */
 
 function test() {
   initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => {
     info("Starting test... ");
 
     let { document, L10N, Editor, NetMonitorView } = aMonitor.panelWin;
     let { RequestsMenu, NetworkDetails } = NetMonitorView;
-
+    let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED;
     RequestsMenu.lazyUpdate = false;
 
-    waitForNetworkEvents(aMonitor, 1).then(() => {
+    Task.spawn(function () {
+      yield waitForNetworkEvents(aMonitor, 1);
       is(RequestsMenu.selectedItem, null,
         "There shouldn't be any selected item in the requests menu.");
       is(RequestsMenu.itemCount, 1,
         "The requests menu should not be empty after the first request.");
       is(NetMonitorView.detailsPaneHidden, true,
         "The details pane should still be hidden after the first request.");
 
       EventUtils.sendMouseEvent({ type: "mousedown" },
@@ -27,25 +28,24 @@ function test() {
 
       isnot(RequestsMenu.selectedItem, null,
         "There should be a selected item in the requests menu.");
       is(RequestsMenu.selectedIndex, 0,
         "The first item should be selected in the requests menu.");
       is(NetMonitorView.detailsPaneHidden, false,
         "The details pane should not be hidden after toggle button was pressed.");
 
+      yield waitFor(aMonitor.panelWin, TAB_UPDATED)
       testHeadersTab();
       testCookiesTab();
       testParamsTab();
-      testResponseTab()
-        .then(() => {
-          testTimingsTab();
-          return teardown(aMonitor);
-        })
-        .then(finish);
+      yield testResponseTab();
+      testTimingsTab();
+      yield teardown(aMonitor);
+      finish();
     });
 
     function testHeadersTab() {
       let tab = document.querySelectorAll("#details-pane tab")[0];
       let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0];
 
       is(tab.getAttribute("selected"), "true",
         "The headers tab in the network details pane should be selected.");
@@ -167,36 +167,39 @@ function test() {
         .hasAttribute("hidden"), true,
         "The request post data textarea box should be hidden.");
     }
 
     function testResponseTab() {
       EventUtils.sendMouseEvent({ type: "mousedown" },
         document.querySelectorAll("#details-pane tab")[3]);
 
-      let tab = document.querySelectorAll("#details-pane tab")[3];
-      let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+      return Task.spawn(function () {
+        yield waitFor(aMonitor.panelWin, TAB_UPDATED);
 
-      is(tab.getAttribute("selected"), "true",
-        "The response tab in the network details pane should be selected.");
+        let tab = document.querySelectorAll("#details-pane tab")[3];
+        let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
+
+        is(tab.getAttribute("selected"), "true",
+          "The response tab in the network details pane should be selected.");
 
-      is(tabpanel.querySelector("#response-content-info-header")
-        .hasAttribute("hidden"), true,
-        "The response info header should be hidden.");
-      is(tabpanel.querySelector("#response-content-json-box")
-        .hasAttribute("hidden"), true,
-        "The response content json box should be hidden.");
-      is(tabpanel.querySelector("#response-content-textarea-box")
-        .hasAttribute("hidden"), false,
-        "The response content textarea box should not be hidden.");
-      is(tabpanel.querySelector("#response-content-image-box")
-        .hasAttribute("hidden"), true,
-        "The response content image box should be hidden.");
+        is(tabpanel.querySelector("#response-content-info-header")
+          .hasAttribute("hidden"), true,
+          "The response info header should be hidden.");
+        is(tabpanel.querySelector("#response-content-json-box")
+          .hasAttribute("hidden"), true,
+          "The response content json box should be hidden.");
+        is(tabpanel.querySelector("#response-content-textarea-box")
+          .hasAttribute("hidden"), false,
+          "The response content textarea box should not be hidden.");
+        is(tabpanel.querySelector("#response-content-image-box")
+          .hasAttribute("hidden"), true,
+          "The response content image box should be hidden.");
 
-      return NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
+        let aEditor = yield NetMonitorView.editor("#response-content-textarea");
         is(aEditor.getText(), "Hello world!",
           "The text shown in the source editor is incorrect.");
         is(aEditor.getMode(), Editor.modes.text,
           "The mode active in the source editor is incorrect.");
       });
     }
 
     function testTimingsTab() {
--- a/browser/devtools/netmonitor/test/head.js
+++ b/browser/devtools/netmonitor/test/head.js
@@ -1,16 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-let { Promise: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
+let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
 let TargetFactory = devtools.TargetFactory;
 let Toolbox = devtools.Toolbox;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/";
 
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
@@ -277,8 +278,25 @@ function verifyRequestItemTarget(aReques
     } else {
       ok(!aRequestItem.target.hasAttribute("even"),
         "Unexpected 'even' attribute for " + aRequestItem.value);
       ok(aRequestItem.target.hasAttribute("odd"),
         "Unexpected 'odd' attribute for " + aRequestItem.value);
     }
   }
 }
+
+/**
+ * Helper function for waiting for an event to fire before resolving a promise.
+ * Example: waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED);
+ *
+ * @param object subject
+ *        The event emitter object that is being listened to.
+ * @param string eventName
+ *        The name of the event to listen to.
+ * @return object
+ *        Returns a promise that resolves upon firing of the event.
+ */
+function waitFor (subject, eventName) {
+  let deferred = promise.defer();
+  subject.once(eventName, deferred.resolve);
+  return deferred.promise;
+}
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -171,17 +171,17 @@ function ResponsiveUI(aWindow, aTab)
   this.bound_startResizing = this.startResizing.bind(this);
   this.bound_stopResizing = this.stopResizing.bind(this);
   this.bound_onDrag = this.onDrag.bind(this);
   this.bound_onKeypress = this.onKeypress.bind(this);
 
   // Events
   this.tab.addEventListener("TabClose", this);
   this.tabContainer.addEventListener("TabSelect", this);
-  this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, false);
+  this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, true);
 
   this.buildUI();
   this.checkMenus();
 
   this.docShell = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIWebNavigation)
                       .QueryInterface(Ci.nsIDocShell);
 
@@ -271,17 +271,17 @@ ResponsiveUI.prototype = {
                 "max-height: none;" +
                 "min-height: 0;";
     this.stack.setAttribute("style", style);
 
     if (this.isResizing)
       this.stopResizing();
 
     // Remove listeners.
-    this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, false);
+    this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, true);
     this.menulist.removeEventListener("select", this.bound_presetSelected, true);
     this.tab.removeEventListener("TabClose", this);
     this.tabContainer.removeEventListener("TabSelect", this);
     this.rotatebutton.removeEventListener("command", this.bound_rotate, true);
     this.screenshotbutton.removeEventListener("command", this.bound_screenshot, true);
     this.touchbutton.removeEventListener("command", this.bound_touch, true);
     this.closebutton.removeEventListener("command", this.bound_close, true);
     this.addbutton.removeEventListener("command", this.bound_addPreset, true);
--- 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/browser/locales/en-US/chrome/browser/places/places.properties
+++ b/browser/locales/en-US/chrome/browser/places/places.properties
@@ -65,16 +65,19 @@ detailsPane.noItems=No items
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 number of items
 # example: 111 items
 detailsPane.itemsCountLabel=One item;#1 items
 
 mostVisitedTitle=Most Visited
 recentlyBookmarkedTitle=Recently Bookmarked
 recentTagsTitle=Recent Tags
+# LOCALIZATION NOTE (firefoxTouchTitle): this is the name of the folder used
+# to store bookmarks created in Metro mode and share bookmarks between Metro
+# and Desktop.
 firefoxTouchTitle=Firefox Touch
 
 OrganizerQueryHistory=History
 OrganizerQueryDownloads=Downloads
 OrganizerQueryAllBookmarks=All Bookmarks
 OrganizerQueryTags=Tags
 
 # LOCALIZATION NOTE (tagResultLabel) :
--- a/browser/themes/shared/devtools/responsivedesign.inc.css
+++ b/browser/themes/shared/devtools/responsivedesign.inc.css
@@ -12,16 +12,20 @@
 }
 
 .browserStack[responsivemode] {
   box-shadow: 0 0 7px black;
 }
 
 .devtools-responsiveui-toolbar {
   background: transparent;
+  /* text color is textColor from dark theme, since no theme is applied to
+   * the responsive toolbar.
+   */
+  color: hsl(210,30%,85%);
   margin: 10px 0;
   padding: 0;
   box-shadow: none;
   border-bottom-width: 0;
 }
 
 .devtools-responsiveui-toolbar > menulist,
 .devtools-responsiveui-toolbar > toolbarbutton {
--- a/mobile/android/base/tests/StringHelper.java
+++ b/mobile/android/base/tests/StringHelper.java
@@ -43,16 +43,23 @@ class StringHelper {
         "Open in New Tab",
         "Open in Private Tab",
         "Edit",
         "Remove",
         "Share",
         "Add to Home Screen"
     };
 
+    public static final String[] CONTEXT_MENU_ITEMS_IN_URL_BAR = new String[] {
+        "Share",
+        "Copy Address",
+        "Edit Site Settings",
+        "Add to Home Screen"
+    };
+
     public static final String TITLE_PLACE_HOLDER = "Enter Search or Address";
 
     // Robocop page urls
     // Note: please use getAbsoluteUrl(String url) on each robocop url to get the correct url
     public static final String ROBOCOP_BIG_LINK_URL = "/robocop/robocop_big_link.html";
     public static final String ROBOCOP_BIG_MAILTO_URL = "/robocop/robocop_big_mailto.html";
     public static final String ROBOCOP_BLANK_PAGE_01_URL = "/robocop/robocop_blank_01.html";
     public static final String ROBOCOP_BLANK_PAGE_02_URL = "/robocop/robocop_blank_02.html";
--- a/mobile/android/base/tests/testClearPrivateData.java
+++ b/mobile/android/base/tests/testClearPrivateData.java
@@ -1,48 +1,117 @@
 package org.mozilla.gecko.tests;
-
+import android.view.View;
 import org.mozilla.gecko.*;
 import java.util.ArrayList;
 
+/**
+ * This patch tests the clear private data options:
+ * - clear history option by: adding and checking that clear private
+ * data option removes the history items but not the users bookmarks
+ * - clear site settings and clear saved password by: checking
+ * each option present in the doorhanger and clearing the settings from
+ * the URL bar context menu and settings menu
+ */
+
 public class testClearPrivateData extends PixelTest {
     private final int TEST_WAIT_MS = 10000;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testClearPrivateData() {
         blockForGeckoReady();
         clearHistory();
+        clearSiteSettings();
+        clearPassword();
     }
 
     private void clearHistory() {
+
         // Loading a page and adding a second one as bookmark to have user made bookmarks and history
         String blank1 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
         String blank2 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL);
-
-        loadAndPaint(blank1);
-        waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE);
-
+        String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE;
+        inputAndLoadUrl(blank1);
+        verifyPageTitle(title);
         mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
 
         // Checking that the history list is not empty
         verifyHistoryCount(1);
-        clearPrivateData();
+
+        //clear and check for device
+        checkDevice(title);
 
         // Checking that history list is empty
         verifyHistoryCount(0);
 
         // Checking that the user made bookmark is not removed
         mAsserter.ok(mDatabaseHelper.isBookmark(blank2), "Checking that bookmarks have not been removed", "User made bookmarks were not removed with private data");
     }
 
     private void verifyHistoryCount(final int expectedCount) {
         boolean match = waitForTest( new BooleanTest() {
             public boolean test() {
                 return (mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY).size() == expectedCount);
             }
         }, TEST_WAIT_MS);
         mAsserter.ok(match, "Checking that the number of history items is correct", String.valueOf(expectedCount) + " history items present in the database");
     }
+
+    public void clearSiteSettings() {
+        String shareStrings[] = {"Share your location with", "Share", "Don't share", "There are no settings to clear"};
+        String titleGeolocation = StringHelper.ROBOCOP_GEOLOCATION_TITLE;
+        String url = getAbsoluteUrl(StringHelper.ROBOCOP_GEOLOCATION_URL);
+        loadCheckDismiss(shareStrings[1], url, shareStrings[0]);
+        checkOption(shareStrings[1], "Clear");
+        checkOption(shareStrings[3], "Cancel");
+        loadCheckDismiss(shareStrings[2], url, shareStrings[0]);
+        checkOption(shareStrings[2], "Cancel");
+        checkDevice(titleGeolocation);
+    }
+
+    public void clearPassword(){
+        String passwordStrings[] = {"Save password", "Save", "Don't save"};
+        String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE;
+        String loginUrl = getAbsoluteUrl(StringHelper.ROBOCOP_LOGIN_URL);
+        loadCheckDismiss(passwordStrings[1], loginUrl, passwordStrings[0]);
+        checkOption(passwordStrings[1], "Clear");
+        loadCheckDismiss(passwordStrings[2], loginUrl, passwordStrings[0]);
+        checkDevice(title);
+    }
+
+    // clear private data and verify the device type because for phone there is an extra back action to exit the settings menu
+    public void checkDevice(String title) {
+        clearPrivateData();
+        if (mDevice.type.equals("phone")) {
+            mActions.sendSpecialKey(Actions.SpecialKey.BACK);
+            mAsserter.ok(waitForText(StringHelper.PRIVACY_SECTION_LABEL), "waiting to perform one back", "one back");
+            mActions.sendSpecialKey(Actions.SpecialKey.BACK);
+            verifyPageTitle(title);
+        }
+        else {
+            mActions.sendSpecialKey(Actions.SpecialKey.BACK);
+            verifyPageTitle(title);
+        }
+    }
+   
+    // Load a URL, verify that the doorhanger appears and dismiss it
+    public void loadCheckDismiss(String option, String url, String message) {
+        inputAndLoadUrl(url);
+        waitForText(message);
+        mAsserter.is(mSolo.searchText(message), true, "Doorhanger:" + message + " has been displayed");
+        mSolo.clickOnButton(option);
+        mAsserter.is(mSolo.searchText(message), false, "Doorhanger:" + message + " has been hidden");
+    }
+
+    //Verify if there are settings to be clear if so clear them from the URL bar context menu
+    public void checkOption(String option, String button) {
+        final View toolbarView = mSolo.getView("browser_toolbar");
+        mSolo.clickLongOnView(toolbarView);
+        mAsserter.ok(waitForText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]), "Waiting for the pop-up to open", "Pop up was openend");
+        mSolo.clickOnText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]);
+        mAsserter.ok(waitForText(option), "Verify that the option: " + option + " is in the list", "The option is in the list. There are settings to clear");
+        mSolo.clickOnButton(button);
+    }
 }
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -34,22 +34,25 @@
 // Filename of the database.
 #define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite")
 // Filename used to backup corrupt databases.
 #define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt")
 
 // Set when the database file was found corrupt by a previous maintenance.
 #define PREF_FORCE_DATABASE_REPLACEMENT "places.database.replaceOnStartup"
 
+// Set to specify the size of the places database growth increments in kibibytes
+#define PREF_GROWTH_INCREMENT_KIB "places.database.growthIncrementKiB"
+
 // Maximum size for the WAL file.  It should be small enough since in case of
 // crashes we could lose all the transactions in the file.  But a too small
 // file could hurt performance.
 #define DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES 512
 
-#define BYTES_PER_MEBIBYTE 1048576
+#define BYTES_PER_KIBIBYTE 1024
 
 // Old Sync GUID annotation.
 #define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid")
 
 // Places string bundle, contains internationalized bookmark root names.
 #define PLACES_BUNDLE "chrome://places/locale/places.properties"
 
 // Livemarks annotations.
@@ -587,18 +590,23 @@ Database::InitSchema(bool* aDatabaseMigr
   // mobile devices, limit its size.
   // Since exceeding the limit will cause a truncate, allow a slightly
   // larger limit than DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES to reduce the number
   // of times it is needed.
   nsAutoCString journalSizePragma("PRAGMA journal_size_limit = ");
   journalSizePragma.AppendInt(DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES * 3);
   (void)mMainConn->ExecuteSimpleSQL(journalSizePragma);
 
-  // Grow places in 10MiB increments to limit fragmentation on disk.
-  (void)mMainConn->SetGrowthIncrement(10 * BYTES_PER_MEBIBYTE, EmptyCString());
+  // Grow places in |growthIncrementKiB| increments to limit fragmentation on disk.
+  // By default, it's 10 MB.
+  int32_t growthIncrementKiB =
+    Preferences::GetInt(PREF_GROWTH_INCREMENT_KIB, 10 * BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE);
+  if (growthIncrementKiB > 0) {
+    (void)mMainConn->SetGrowthIncrement(growthIncrementKiB * BYTES_PER_KIBIBYTE, EmptyCString());
+  }
 
   // We use our functions during migration, so initialize them now.
   rv = InitFunctions();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get the database schema version.
   int32_t currentSchemaVersion;
   rv = mMainConn->GetSchemaVersion(&currentSchemaVersion);
--- a/toolkit/devtools/Loader.jsm
+++ b/toolkit/devtools/Loader.jsm
@@ -30,16 +30,17 @@ this.EXPORTED_SYMBOLS = ["DevToolsLoader
 /**
  * Providers are different strategies for loading the devtools.
  */
 
 let loaderGlobals = {
   btoa: btoa,
   console: console,
   _Iterator: Iterator,
+  ChromeWorker: ChromeWorker,
   loader: {
     lazyGetter: XPCOMUtils.defineLazyGetter.bind(XPCOMUtils),
     lazyImporter: XPCOMUtils.defineLazyModuleGetter.bind(XPCOMUtils),
     lazyServiceGetter: XPCOMUtils.defineLazyServiceGetter.bind(XPCOMUtils)
   }
 };
 
 // Used when the tools should be loaded from the Firefox package itself (the default)
--- 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);
@@ -248,17 +253,21 @@ RootActor.prototype = {
           selected = tabActorList.length;
         }
         tabActor.parentID = this.actorID;
         newActorPool.addActor(tabActor);
         tabActorList.push(tabActor);
       }
 
       /* DebuggerServer.addGlobalActor support: create actors. */
-      this._createExtraActors(this._parameters.globalActorFactories, newActorPool);
+      if (!this._globalActorPool) {
+        this._globalActorPool = new ActorPool(this.conn);
+        this._createExtraActors(this._parameters.globalActorFactories, this._globalActorPool);
+        this.conn.addActorPool(this._globalActorPool);
+      }
 
       /*
        * Drop the old actorID -> actor map. Actors that still mattered were
        * added to the new map; others will go away.
        */
       if (this._tabActorPool) {
         this.conn.removeActorPool(this._tabActorPool);
       }
@@ -266,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);
 });
--- a/toolkit/devtools/server/dbg-server.jsm
+++ b/toolkit/devtools/server/dbg-server.jsm
@@ -10,36 +10,16 @@
  * shield it from the debuggee. This way, when debugging chrome globals,
  * debugger and debuggee will be in separate compartments.
  */
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
+const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+
 this.EXPORTED_SYMBOLS = ["DebuggerServer", "ActorPool"];
 
-var loadSubScript =
-  "function loadSubScript(aURL)\n" +
-  "{\n" +
-  "const Ci = Components.interfaces;\n" +
-  "const Cc = Components.classes;\n" +
-  "  try {\n" +
-  "    let loader = Cc[\"@mozilla.org/moz/jssubscript-loader;1\"]\n" +
-  "      .getService(Ci.mozIJSSubScriptLoader);\n" +
-  "    loader.loadSubScript(aURL, this);\n" +
-  "  } catch(e) {\n" +
-  "    dump(\"Error loading: \" + aURL + \": \" + e + \" - \" + e.stack + \"\\n\");\n" +
-  "    throw e;\n" +
-  "  }\n" +
-  "}";
+let server = devtools.require("devtools/server/main");
 
-// Load the debugging server in a sandbox with its own compartment.
-var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
-                      .createInstance(Ci.nsIPrincipal);
-
-var gGlobal = Cu.Sandbox(systemPrincipal);
-gGlobal.ChromeWorker = ChromeWorker;
-Cu.evalInSandbox(loadSubScript, gGlobal, "1.8");
-gGlobal.loadSubScript("resource://gre/modules/devtools/server/main.js");
-
-this.DebuggerServer = gGlobal.DebuggerServer;
-this.ActorPool = gGlobal.ActorPool;
+this.DebuggerServer = server.DebuggerServer;
+this.ActorPool = server.ActorPool;
--- a/toolkit/devtools/server/main.js
+++ b/toolkit/devtools/server/main.js
@@ -5,46 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 /**
  * Toolkit glue for the remote debugging protocol, loaded into the
  * debugging global.
  */
 
-// |this.require| is used to test if this file was loaded via the devtools
-// loader (as it is in DebuggerProcess.jsm) or via loadSubScript (as it is from
-// dbg-server.jsm).  Note that testing |require| is not safe in either
-// situation, as it causes a ReferenceError.
-var Ci, Cc, CC, Cu, Cr, Components;
-if (this.require) {
-  ({ Ci, Cc, CC, Cu, Cr, components: Components }) = require("chrome");
-} else {
-  ({
-    interfaces: Ci,
-    classes: Cc,
-    Constructor: CC,
-    utils: Cu,
-    results: Cr
-  }) = Components;
-}
-
-// On B2G, if |this.require| is undefined at this point, it remains undefined
-// later on when |DebuggerServer.registerModule| is called.  On desktop (and
-// perhaps other places), if |this.require| starts out undefined, it ends up
-// being set to some native code by the time we get to |registerModule|.  Here
-// we perform a test early on, and then cache the correct require function for
-// later use.
-var localRequire;
-if (this.require) {
-  localRequire = id => require(id);
-} else {
-  let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
-  localRequire = id => devtools.require(id);
-}
+// Until all Debugger server code is converted to SDK modules,
+// imports Components.* alias from chrome module.
+var { Ci, Cc, CC, Cu, Cr } = require("chrome");
+// On B2G, `this` != Global scope, so `Ci` won't be binded on `this`
+// (i.e. this.Ci is undefined) Then later, when using loadSubScript,
+// Ci,... won't be defined for sub scripts.
+this.Ci = Ci;
+this.Cc = Cc;
+this.CC = CC;
+this.Cu = Cu;
+this.Cr = Cr;
+// Overload `Components` to prevent SDK loader exception on Components
+// object usage
+Object.defineProperty(this, "Components", {
+  get: function () require("chrome").components
+});
 
 const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties";
 
 const nsFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
 Cu.import("resource://gre/modules/reflect.jsm");
 Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -63,36 +49,40 @@ function loadSubScript(aURL)
   } catch(e) {
     let errorStr = "Error loading: " + aURL + ": " + e + " - " + e.stack + "\n";
     dump(errorStr);
     Cu.reportError(errorStr);
     throw e;
   }
 }
 
-let loaderRequire = this.require;
-this.require = null;
-loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js");
-this.require = loaderRequire;
+let {defer, resolve, reject, promised, all} = require("sdk/core/promise");
+this.defer = defer;
+this.resolve = resolve;
+this.reject = reject;
+this.promised = promised;
+this.all = all;
 
 Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
 
 loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js");
 
 function dumpn(str) {
   if (wantLogging) {
     dump("DBG-SERVER: " + str + "\n");
   }
 }
+this.dumpn = dumpn;
 
 function dbg_assert(cond, e) {
   if (!cond) {
     return e;
   }
 }
+this.dbg_assert = dbg_assert;
 
 loadSubScript.call(this, "resource://gre/modules/devtools/server/transport.js");
 
 // XPCOM constructors
 const ServerSocket = CC("@mozilla.org/network/server-socket;1",
                         "nsIServerSocket",
                         "initSpecialConnection");
 const UnixDomainServerSocket = CC("@mozilla.org/network/server-socket;1",
@@ -319,17 +309,17 @@ var DebuggerServer = {
    *    'register' and 'unregister' functions.
    */
   registerModule: function(id) {
     if (id in gRegisteredModules) {
       throw new Error("Tried to register a module twice: " + id + "\n");
     }
 
     let moduleAPI = ModuleAPI();
-    let mod = localRequire(id);
+    let mod = require(id);
     mod.register(moduleAPI);
     gRegisteredModules[id] = { module: mod, api: moduleAPI };
   },
 
   /**
    * Returns true if a module id has been registered.
    */
   isModuleRegistered: function(id) {
@@ -683,16 +673,18 @@ var DebuggerServer = {
       }
     }
   }
 };
 
 if (this.exports) {
   exports.DebuggerServer = DebuggerServer;
 }
+// Needed on B2G (See header note)
+this.DebuggerServer = DebuggerServer;
 
 /**
  * Construct an ActorPool.
  *
  * ActorPools are actorID -> actor mapping and storage.  These are
  * used to accumulate and quickly dispose of groups of actors that
  * share a lifetime.
  */
@@ -701,16 +693,18 @@ function ActorPool(aConnection)
   this.conn = aConnection;
   this._cleanups = {};
   this._actors = {};
 }
 
 if (this.exports) {
   exports.ActorPool = ActorPool;
 }
+// Needed on B2G (See header note)
+this.ActorPool = ActorPool;
 
 ActorPool.prototype = {
   /**
    * Add an actor to the actor pool.  If the actor doesn't have an ID,
    * allocate one from the connection.
    *
    * @param aActor object
    *        The actor implementation.  If the object has a
--- a/toolkit/devtools/server/tests/unit/test_add_actors.js
+++ b/toolkit/devtools/server/tests/unit/test_add_actors.js
@@ -22,16 +22,17 @@ function run_test()
   DebuggerServer.addActors("resource://test/post_init_global_actors.js");
   DebuggerServer.addActors("resource://test/post_init_tab_actors.js");
 
   add_test(init);
   add_test(test_pre_init_global_actor);
   add_test(test_pre_init_tab_actor);
   add_test(test_post_init_global_actor);
   add_test(test_post_init_tab_actor);
+  add_test(test_stable_global_actor_instances);
   add_test(close_client);
   run_next_test();
 }
 
 function init()
 {
   gClient = new DebuggerClient(DebuggerServer.connectPipe());
   gClient.connect(function onConnect() {
@@ -77,11 +78,30 @@ function test_post_init_tab_actor()
   gClient.request({ to: gActors.postInitTabActor, type: "ping" },
     function onResponse(aResponse) {
       do_check_eq(aResponse.message, "pong");
       run_next_test();
     }
   );
 }
 
+// Get the object object, from the server side, for a given actor ID
+function getActorInstance(connID, actorID) {
+  return DebuggerServer._connections[connID].getActor(actorID);
+}
+
+function test_stable_global_actor_instances()
+{
+  // Consider that there is only one connection,
+  // and the first one is ours
+  let connID = Object.keys(DebuggerServer._connections)[0];
+  let postInitGlobalActor = getActorInstance(connID, gActors.postInitGlobalActor);
+  let preInitGlobalActor = getActorInstance(connID, gActors.preInitGlobalActor);
+  gClient.listTabs(function onListTabs(aResponse) {
+    do_check_eq(postInitGlobalActor, getActorInstance(connID, aResponse.postInitGlobalActor));
+    do_check_eq(preInitGlobalActor, getActorInstance(connID, aResponse.preInitGlobalActor));
+    run_next_test();
+  });
+}
+
 function close_client() {
   gClient.close(() => run_next_test());
 }
--- a/webapprt/prefs.js
+++ b/webapprt/prefs.js
@@ -78,8 +78,9 @@ pref("devtools.debugger.force-local", tr
 pref("dom.ipc.plugins.enabled.i386", false);
 pref("dom.ipc.plugins.enabled.i386.flash player.plugin", true);
 // x86_64 ipc preferences
 pref("dom.ipc.plugins.enabled.x86_64", true);
 #else
 pref("dom.ipc.plugins.enabled", true);
 #endif
 
+pref("places.database.growthIncrementKiB", 0);