merge m-c to fx-team
authorTim Taubert <ttaubert@mozilla.com>
Fri, 19 Apr 2013 09:42:19 +0200
changeset 129241 64d6d002e888b13d7ab4ed466aed528ca301e737
parent 129234 f8d27fe5d7c04b396b6798255b35aa384401e04c (current diff)
parent 129240 ef07def8f9579c5cddb32de928ff7e3bec0fe4e0 (diff)
child 129250 fd264d55113047884e1f3f7d440d7968e0916755
child 129257 1e16b3af2489340594279ec5e4335618c7689666
child 129302 e1198271a9a6175256fc556383fcba468fca48f8
push id24563
push userttaubert@mozilla.com
push dateFri, 19 Apr 2013 07:42:17 +0000
treeherdermozilla-central@64d6d002e888 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.0a1
first release with
nightly linux32
64d6d002e888 / 23.0a1 / 20130419030957 / files
nightly linux64
64d6d002e888 / 23.0a1 / 20130419030957 / files
nightly mac
64d6d002e888 / 23.0a1 / 20130419030957 / files
nightly win32
64d6d002e888 / 23.0a1 / 20130419030957 / files
nightly win64
64d6d002e888 / 23.0a1 / 20130419030957 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge m-c to fx-team
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1033,16 +1033,17 @@ pref("devtools.commands.dir", "");
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
 pref("devtools.toolbox.selectedTool", "webconsole");
 pref("devtools.toolbox.toolbarSpec", '["paintflashing toggle","tilt toggle","scratchpad","resize toggle"]');
 pref("devtools.toolbox.sideEnabled", true);
+pref("devtools.toolbox.disabledTools", "[]");
 
 // Enable the Inspector
 pref("devtools.inspector.enabled", true);
 pref("devtools.inspector.activeSidebar", "ruleview");
 pref("devtools.inspector.markupPreview", false);
 
 // Enable the Layout View
 pref("devtools.layoutview.enabled", true);
--- a/browser/devtools/commandline/BuiltinCommands.jsm
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -43,136 +43,165 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   });
 
   /**
   * 'addon list' command.
   */
   gcli.addCommand({
     name: "addon list",
     description: gcli.lookup("addonListDesc"),
+    returnType: "addonsInfo",
     params: [{
       name: 'type',
       type: {
         name: 'selection',
         data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
       },
       defaultValue: 'all',
-      description: gcli.lookup("addonListTypeDesc"),
+      description: gcli.lookup("addonListTypeDesc")
     }],
     exec: function(aArgs, context) {
-      function representEnabledAddon(aAddon) {
-        return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
-        getAddonStatus(aAddon) + "]]></li>";
+      let deferred = context.defer();
+      function pendingOperations(aAddon) {
+        let allOperations = ["PENDING_ENABLE",
+                             "PENDING_DISABLE",
+                             "PENDING_UNINSTALL",
+                             "PENDING_INSTALL",
+                             "PENDING_UPGRADE"];
+        return allOperations.reduce(function(operations, opName) {
+          return aAddon.pendingOperations & AddonManager[opName] ?
+            operations.concat(opName) :
+            operations;
+        }, []);
       }
+      let types = aArgs.type === "all" ? null : [aArgs.type];
+      AddonManager.getAddonsByTypes(types, function(addons) {
+        deferred.resolve({
+          addons: addons.map(function(addon) {
+            return {
+              name: addon.name,
+              version: addon.version,
+              isActive: addon.isActive,
+              pendingOperations: pendingOperations(addon)
+            };
+          }),
+          type: aArgs.type
+        });
+      });
+      return deferred.promise;
+    }
+  });
 
-      function representDisabledAddon(aAddon) {
-        return "<li class=\"gcli-addon-disabled\">" +
-          "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
-          "]]></li>";
+  gcli.addConverter({
+    from: "addonsInfo",
+    to: "view",
+    exec: function(addonsInfo, context) {
+      if (!addonsInfo.addons.length) {
+        return context.createView({
+          html: "<p>${message}</p>",
+          data: { message: gcli.lookup("addonNoneOfType") }
+        });
       }
 
-      function getAddonStatus(aAddon) {
-        let operations = [];
-
-        if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
-          operations.push("PENDING_ENABLE");
-        }
-
-        if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
-          operations.push("PENDING_DISABLE");
-        }
+      let headerLookups = {
+        "dictionary": "addonListDictionaryHeading",
+        "extension": "addonListExtensionHeading",
+        "locale": "addonListLocaleHeading",
+        "plugin": "addonListPluginHeading",
+        "theme": "addonListThemeHeading",
+        "all": "addonListAllHeading"
+      };
+      let header = gcli.lookup(headerLookups[addonsInfo.type] ||
+                               "addonListUnknownHeading");
 
-        if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
-          operations.push("PENDING_UNINSTALL");
-        }
-
-        if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
-          operations.push("PENDING_INSTALL");
-        }
-
-        if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
-          operations.push("PENDING_UPGRADE");
-        }
-
-        if (operations.length) {
-          return " (" + operations.join(", ") + ")";
-        }
-        return "";
+      let operationLookups = {
+        "PENDING_ENABLE": "addonPendingEnable",
+        "PENDING_DISABLE": "addonPendingDisable",
+        "PENDING_UNINSTALL": "addonPendingUninstall",
+        "PENDING_INSTALL": "addonPendingInstall",
+        "PENDING_UPGRADE": "addonPendingUpgrade"
+      };
+      function lookupOperation(opName) {
+        let lookupName = operationLookups[opName];
+        return lookupName ? gcli.lookup(lookupName) : opName;
       }
 
-      /**
-      * Compares two addons by their name. Used in sorting.
-      */
-      function compareAddonNames(aNameA, aNameB) {
-        return String.localeCompare(aNameA.name, aNameB.name);
-      }
-
-      /**
-      * Resolves the promise which is the scope (this) of this function, filling
-      * it with an HTML representation of the passed add-ons.
-      */
-      function list(aType, aAddons) {
-        if (!aAddons.length) {
-          this.resolve(gcli.lookup("addonNoneOfType"));
-        }
-
-        // Separate the enabled add-ons from the disabled ones.
+      function arrangeAddons(addons) {
         let enabledAddons = [];
         let disabledAddons = [];
-
-        aAddons.forEach(function(aAddon) {
+        addons.forEach(function(aAddon) {
           if (aAddon.isActive) {
             enabledAddons.push(aAddon);
           } else {
             disabledAddons.push(aAddon);
           }
         });
 
-        let header;
-        switch(aType) {
-          case "dictionary":
-            header = gcli.lookup("addonListDictionaryHeading");
-            break;
-          case "extension":
-            header = gcli.lookup("addonListExtensionHeading");
-            break;
-          case "locale":
-            header = gcli.lookup("addonListLocaleHeading");
-            break;
-          case "plugin":
-            header = gcli.lookup("addonListPluginHeading");
-            break;
-          case "theme":
-            header = gcli.lookup("addonListThemeHeading");
-          case "all":
-            header = gcli.lookup("addonListAllHeading");
-            break;
-          default:
-            header = gcli.lookup("addonListUnknownHeading");
+        function compareAddonNames(aNameA, aNameB) {
+          return String.localeCompare(aNameA.name, aNameB.name);
         }
+        enabledAddons.sort(compareAddonNames);
+        disabledAddons.sort(compareAddonNames);
 
-        // Map and sort the add-ons, and create an HTML list.
-        let message = header +
-                      "<ol>" +
-                      enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
-                      disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
-                      "</ol>";
+        return enabledAddons.concat(disabledAddons);
+      }
 
-        this.resolve(context.createView({ html: message }));
+      function isActiveForToggle(addon) {
+        return (addon.isActive && ~~addon.pendingOperations.indexOf("PENDING_DISABLE"));
       }
 
-      // Create the promise that will be resolved when the add-on listing has
-      // been finished.
-      let deferred = context.defer();
-      let types = aArgs.type == "all" ? null : [aArgs.type];
-      AddonManager.getAddonsByTypes(types, list.bind(deferred, aArgs.type));
-      return deferred.promise;
+      return context.createView({
+        html: addonsListHtml,
+        data: {
+          header: header,
+          addons: arrangeAddons(addonsInfo.addons).map(function(addon) {
+            return {
+              name: addon.name,
+              label: addon.name.replace(/\s/g, "_") +
+                    (addon.version ? "_" + addon.version : ""),
+              status: addon.isActive ? "enabled" : "disabled",
+              version: addon.version,
+              pendingOperations: addon.pendingOperations.length ?
+                (" (" + gcli.lookup("addonPending") + ": "
+                 + addon.pendingOperations.map(lookupOperation).join(", ")
+                 + ")") :
+                "",
+              toggleActionName: isActiveForToggle(addon) ? "disable": "enable",
+              toggleActionMessage: isActiveForToggle(addon) ?
+                gcli.lookup("addonListOutDisable") :
+                gcli.lookup("addonListOutEnable")
+            };
+          }),
+          onclick: createUpdateHandler(context),
+          ondblclick: createExecuteHandler(context)
+        }
+      });
     }
   });
 
+  var addonsListHtml = "" +
+        "<table>" +
+        " <caption>${header}</caption>" +
+        " <tbody>" +
+        "  <tr foreach='addon in ${addons}'" +
+        "      class=\"gcli-addon-${addon.status}\">" +
+        "    <td>${addon.name} ${addon.version}</td>" +
+        "    <td>${addon.pendingOperations}</td>" +
+        "    <td>" +
+        "      <span class='gcli-out-shortcut'" +
+        "            data-command='addon ${addon.toggleActionName} ${addon.label}'" +
+        "       onclick='${onclick}'" +
+        "       ondblclick='${ondblclick}'" +
+        "      >${addon.toggleActionMessage}</span>" +
+        "    </td>" +
+        "  </tr>" +
+        " </tbody>" +
+        "</table>" +
+        "";
+
   // We need a list of addon names for the enable and disable commands. Because
   // getting the name list is async we do not add the commands until we have the
   // list.
   AddonManager.getAllAddons(function addonAsync(aAddons) {
     // We listen for installs to keep our addon list up to date. There is no need
     // to listen for uninstalls because uninstalled addons are simply disabled
     // until restart (to enable undo functionality).
     AddonManager.addAddonListener({
@@ -305,16 +334,67 @@ XPCOMUtils.defineLazyModuleGetter(this, 
         // List the installed add-ons, disable one when done listing.
         AddonManager.getAllAddons(disable.bind(deferred, aArgs.name));
         return deferred.promise;
       }
     });
     module.CmdAddonFlags.addonsLoaded = true;
     Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
   });
+
+  /**
+   * Helper to find the 'data-command' attribute and call some action on it.
+   * @see |updateCommand()| and |executeCommand()|
+   */
+  function withCommand(element, action) {
+    var command = element.getAttribute("data-command");
+    if (!command) {
+      command = element.querySelector("*[data-command]")
+        .getAttribute("data-command");
+    }
+
+    if (command) {
+      action(command);
+    }
+    else {
+      console.warn("Missing data-command for " + util.findCssSelector(element));
+    }
+  }
+
+  /**
+   * Create a handler to update the requisition to contain the text held in the
+   * first matching data-command attribute under the currentTarget of the event.
+   * @param context Either a Requisition or an ExecutionContext or another object
+   * that contains an |update()| function that follows a similar contract.
+   */
+  function createUpdateHandler(context) {
+    return function(ev) {
+      withCommand(ev.currentTarget, function(command) {
+        context.update(command);
+      });
+    }
+  }
+
+  /**
+   * Create a handler to execute the text held in the data-command attribute
+   * under the currentTarget of the event.
+   * @param context Either a Requisition or an ExecutionContext or another object
+   * that contains an |update()| function that follows a similar contract.
+   */
+  function createExecuteHandler(context) {
+    return function(ev) {
+      withCommand(ev.currentTarget, function(command) {
+        context.exec({
+          visible: true,
+          typed: command
+        });
+      });
+    }
+  }
+
 }(this));
 
 /* CmdCalllog -------------------------------------------------------------- */
 
 (function(module) {
   XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
     let JsDebugger = {};
     Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -195,20 +195,16 @@
     <key id="globalSearchKey"
          key="&debuggerUI.searchGlobal.key;"
          modifiers="accel alt"
          command="globalSearchCommand"/>
     <key id="functionSearchKey"
          key="&debuggerUI.searchFunction.key;"
          modifiers="accel"
          command="functionSearchCommand"/>
-    <key id="functionSearchKey"
-         key="&debuggerUI.searchFunction.altkey;"
-         modifiers="accel shift"
-         command="functionSearchCommand"/>
     <key id="tokenSearchKey"
          key="&debuggerUI.searchToken.key;"
          modifiers="accel"
          command="tokenSearchCommand"/>
     <key id="lineSearchKey"
          key="&debuggerUI.searchLine.key;"
          modifiers="accel"
          command="lineSearchCommand"/>
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -130,17 +130,17 @@ this.Toolbox = function Toolbox(target, 
 
   if (!hostType) {
     hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
   }
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
   }
   let definitions = gDevTools.getToolDefinitionMap();
-  if (!definitions.get(selectedTool)) {
+  if (!definitions.get(selectedTool) && selectedTool != "options") {
     selectedTool = "webconsole";
   }
   this._defaultToolId = selectedTool;
 
   this._host = this._createHost(hostType);
 
   EventEmitter.decorate(this);
 
@@ -258,16 +258,17 @@ Toolbox.prototype = {
         iframe.removeEventListener("DOMContentLoaded", domReady, true);
 
         this.isReady = true;
 
         let closeButton = this.doc.getElementById("toolbox-close");
         closeButton.addEventListener("command", this.destroy, true);
 
         this._buildDockButtons();
+        this._buildOptions();
         this._buildTabs();
         this._buildButtons();
         this._addKeysToWindow();
 
         this.selectTool(this._defaultToolId).then(function(panel) {
           this.emit("ready");
           deferred.resolve();
         }.bind(this));
@@ -275,25 +276,40 @@ Toolbox.prototype = {
 
       iframe.addEventListener("DOMContentLoaded", domReady, true);
       iframe.setAttribute("src", this._URL);
     }.bind(this));
 
     return deferred.promise;
   },
 
+  _buildOptions: function TBOX__buildOptions() {
+    this.optionsButton = this.doc.getElementById("toolbox-tab-options");
+    this.optionsButton.addEventListener("command", function() {
+      this.selectTool("options");
+    }.bind(this), false);
+
+    let iframe = this.doc.getElementById("toolbox-panel-iframe-options");
+    this._toolPanels.set("options", iframe);
+
+    let key = this.doc.getElementById("toolbox-options-key");
+    key.addEventListener("command", function(toolId) {
+      this.selectTool(toolId);
+    }.bind(this, "options"), true);
+  },
+
   /**
    * Adds the keys and commands to the Toolbox Window in window mode.
    */
   _addKeysToWindow: function TBOX__addKeysToWindow() {
     if (this.hostType != Toolbox.HostType.WINDOW) {
       return;
     }
     let doc = this.doc.defaultView.parent.document;
-    for (let [id, toolDefinition] of gDevTools._tools) {
+    for (let [id, toolDefinition] of gDevTools.getToolDefinitionMap()) {
       if (toolDefinition.key) {
         // Prevent multiple entries for the same tool.
         if (doc.getElementById("key_" + id)) {
           continue;
         }
         let key = doc.createElement("key");
         key.id = "key_" + id;
 
@@ -470,26 +486,40 @@ Toolbox.prototype = {
     let index = -1;
     let tabs = tabstrip.childNodes;
     for (let i = 0; i < tabs.length; i++) {
       if (tabs[i] === tab) {
         index = i;
         break;
       }
     }
-    tabstrip.selectedIndex = index;
+    tabstrip.selectedItem = tab;
 
     // and select the right iframe
     let deck = this.doc.getElementById("toolbox-deck");
-    deck.selectedIndex = index;
+    // offset by 1 due to options panel
+    if (id == "options") {
+      deck.selectedIndex = 0;
+      this.optionsButton.setAttribute("checked", true);
+    }
+    else {
+      deck.selectedIndex = index != -1 ? index + 1: -1;
+      this.optionsButton.removeAttribute("checked");
+    }
 
     let definition = gDevTools.getToolDefinitionMap().get(id);
 
     this._currentToolId = id;
 
+    let resolveSelected = panel => {
+      this.emit("select", id);
+      this.emit(id + "-selected", panel);
+      deferred.resolve(panel);
+    };
+
     let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
     if (!iframe) {
       iframe = this.doc.createElement("iframe");
       iframe.className = "toolbox-panel-iframe";
       iframe.id = "toolbox-panel-iframe-" + id;
       iframe.setAttribute("flex", 1);
       iframe.setAttribute("forceOwnRefreshDriver", "");
       iframe.tooltip = "aHTMLTooltip";
@@ -500,37 +530,43 @@ Toolbox.prototype = {
       let boundLoad = function() {
         iframe.removeEventListener("DOMContentLoaded", boundLoad, true);
 
         let built = definition.build(iframe.contentWindow, this);
         Promise.resolve(built).then(function(panel) {
           this._toolPanels.set(id, panel);
 
           this.emit(id + "-ready", panel);
-          this.emit("select", id);
-          this.emit(id + "-selected", panel);
           gDevTools.emit(id + "-ready", this, panel);
 
-          deferred.resolve(panel);
+          resolveSelected(panel);
         }.bind(this));
       }.bind(this);
 
       iframe.addEventListener("DOMContentLoaded", boundLoad, true);
       iframe.setAttribute("src", definition.url);
     } else {
       let panel = this._toolPanels.get(id);
       // only emit 'select' event if the iframe has been loaded
-      if (panel) {
-        this.emit("select", id);
-        this.emit(id + "-selected", panel);
-        deferred.resolve(panel);
+      if (panel && (!panel.contentDocument ||
+                    panel.contentDocument.readyState == "complete")) {
+        resolveSelected(panel);
+      }
+      else if (panel) {
+        let boundLoad = function() {
+          panel.removeEventListener("DOMContentLoaded", boundLoad, true);
+          resolveSelected(panel);
+        };
+        panel.addEventListener("DOMContentLoaded", boundLoad, true);
       }
     }
 
-    Services.prefs.setCharPref(this._prefs.LAST_TOOL, id);
+    if (id != "options") {
+      Services.prefs.setCharPref(this._prefs.LAST_TOOL, id);
+    }
 
     return deferred.promise;
   },
 
   /**
    * Raise the toolbox host.
    */
   raise: function TBOX_raise() {
@@ -538,18 +574,18 @@ Toolbox.prototype = {
   },
 
   /**
    * Refresh the host's title.
    */
   _refreshHostTitle: function TBOX_refreshHostTitle() {
     let toolName;
     let toolId = this.currentToolId;
-    if (toolId) {
-      let toolDef = gDevTools.getToolDefinitionMap().get(toolId);
+    let toolDef = gDevTools.getToolDefinitionMap().get(toolId);
+    if (toolDef) {
       toolName = toolDef.label;
     } else {
       // no tool is selected
       toolName = toolboxStrings("toolbox.defaultTitle");
     }
     let title = toolboxStrings("toolbox.titleTemplate",
                                toolName, this.target.url);
     this._host.setTitle(title);
@@ -633,16 +669,22 @@ Toolbox.prototype = {
   /**
    * Handler for the tool-unregistered event.
    * @param  {string} event
    *         Name of the event ("tool-unregistered")
    * @param  {string} toolId
    *         Id of the tool that was unregistered
    */
   _toolUnregistered: function TBOX_toolUnregistered(event, toolId) {
+    if (this._toolPanels.has(toolId)) {
+      let instance = this._toolPanels.get(toolId);
+      instance.destroy();
+      this._toolPanels.delete(toolId);
+    }
+
     let radio = this.doc.getElementById("toolbox-tab-" + toolId);
     let panel = this.doc.getElementById("toolbox-panel-" + toolId);
 
     if (radio) {
       if (this._currentToolId == toolId) {
         let nextToolName = null;
         if (radio.nextSibling) {
           nextToolName = radio.nextSibling.getAttribute("toolid");
@@ -663,22 +705,16 @@ Toolbox.prototype = {
 
     if (this.hostType == Toolbox.HostType.WINDOW) {
       let doc = this.doc.defaultView.parent.document;
       let key = doc.getElementById("key_" + id);
       if (key) {
         key.parentNode.removeChild(key);
       }
     }
-
-    if (this._toolPanels.has(toolId)) {
-      let instance = this._toolPanels.get(toolId);
-      instance.destroy();
-      this._toolPanels.delete(toolId);
-    }
   },
 
 
   /**
    * Get the toolbox's notification box
    *
    * @return The notification box element.
    */
@@ -705,16 +741,17 @@ Toolbox.prototype = {
     this.off("select", this._refreshHostTitle);
     this.off("host-changed", this._refreshHostTitle);
 
     gDevTools.off("tool-registered", this._toolRegistered);
     gDevTools.off("tool-unregistered", this._toolUnregistered);
 
     let outstanding = [];
 
+    this._toolPanels.delete("options");
     for (let [id, panel] of this._toolPanels) {
       outstanding.push(panel.destroy());
     }
 
     let container = this.doc.getElementById("toolbox-buttons");
     while(container.firstChild) {
       container.removeChild(container.firstChild);
     }
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -92,36 +92,54 @@ DevTools.prototype = {
   unregisterTool: function DT_unregisterTool(toolId, isQuitApplication) {
     this._tools.delete(toolId);
 
     if (!isQuitApplication) {
       this.emit("tool-unregistered", toolId);
     }
   },
 
+  getDefaultTools: function DT_getDefaultTools() {
+    return defaultTools;
+  },
+
+  getAdditionalTools: function DT_getAdditionalTools() {
+    let tools = [];
+    for (let [key, value] of this._tools) {
+      if (defaultTools.indexOf(value) == -1) {
+        tools.push(value);
+      }
+    }
+    return tools;
+  },
+
   /**
    * Allow ToolBoxes to get at the list of tools that they should populate
    * themselves with.
    *
    * @return {Map} tools
    *         A map of the the tool definitions registered in this instance
    */
   getToolDefinitionMap: function DT_getToolDefinitionMap() {
     let tools = new Map();
+    let disabledTools = [];
+    try {
+      disabledTools = JSON.parse(Services.prefs.getCharPref("devtools.toolbox.disabledTools"));
+    } catch(ex) {}
 
     for (let [key, value] of this._tools) {
       let enabled;
 
       try {
         enabled = Services.prefs.getBoolPref(value.killswitch);
       } catch(e) {
         enabled = true;
       }
 
-      if (enabled) {
+      if (enabled && disabledTools.indexOf(key) == -1) {
         tools.set(key, value);
       }
     }
     return tools;
   },
 
   /**
    * Tools have an inherent ordering that can't be represented in a Map so
--- a/browser/devtools/framework/test/Makefile.in
+++ b/browser/devtools/framework/test/Makefile.in
@@ -18,11 +18,12 @@ MOCHITEST_BROWSER_FILES = \
 		browser_toolbox_hosts.js \
 		browser_toolbox_ready.js \
 		browser_toolbox_select_event.js \
 		browser_target_events.js \
 		browser_toolbox_tool_ready.js \
 		browser_toolbox_sidebar.js \
 		browser_toolbox_window_shortcuts.js \
 		browser_toolbox_window_title_changes.js \
+		browser_toolbox_options.js \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_options.js
@@ -0,0 +1,142 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+let doc = null, toolbox = null, panelWin = null, index = 0, prefValues = [], prefNodes = [];
+
+function test() {
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    gDevTools.showToolbox(target).then(testSelectTool);
+  }, true);
+
+  content.location = "data:text/html,test for dynamically registering and unregistering tools";
+}
+
+function testSelectTool(aToolbox) {
+  toolbox = aToolbox;
+  doc = toolbox.doc;
+  toolbox.once("options-selected", testOptionsShortcut);
+  toolbox.selectTool("options");
+}
+
+function testOptionsShortcut() {
+  ok(true, "Toolbox selected via selectTool method");
+  toolbox.once("options-selected", testOptionsButtonClick);
+  toolbox.selectTool("webconsole")
+         .then(() => synthesizeKeyFromKeyTag("toolbox-options-key", doc));
+}
+
+function testOptionsButtonClick() {
+  ok(true, "Toolbox selected via shortcut");
+  toolbox.once("options-selected", testOptions);
+  toolbox.selectTool("webconsole")
+         .then(() => doc.getElementById("toolbox-tab-options").click());
+}
+
+function testOptions(event, iframe) {
+  ok(true, "Toolbox selected via button click");
+  panelWin = iframe.contentWindow;
+  let panelDoc = iframe.contentDocument;
+  // Testing pref changes
+  let prefCheckboxes = panelDoc.querySelectorAll("checkbox[data-pref]");
+  for (let checkbox of prefCheckboxes) {
+    prefNodes.push(checkbox);
+    prefValues.push(Services.prefs.getBoolPref(checkbox.getAttribute("data-pref")));
+  }
+  // Do again with opposite values to reset prefs
+  for (let checkbox of prefCheckboxes) {
+    prefNodes.push(checkbox);
+    prefValues.push(!Services.prefs.getBoolPref(checkbox.getAttribute("data-pref")));
+  }
+  testMouseClicks();
+}
+
+function testMouseClicks() {
+  if (index == prefValues.length) {
+    checkTools();
+    return;
+  }
+  gDevTools.once("pref-changed", prefChanged);
+  info("Click event synthesized for index " + index);
+  EventUtils.synthesizeMouse(prefNodes[index], 10, 10, {}, panelWin);
+}
+
+function prefChanged(event, data) {
+  if (data.pref == prefNodes[index].getAttribute("data-pref")) {
+    ok(true, "Correct pref was changed");
+    is(data.oldValue, prefValues[index], "Previous value is correct");
+    is(data.newValue, !prefValues[index], "New value is correct");
+    index++;
+    testMouseClicks();
+    return;
+  }
+  ok(false, "Pref was not changed correctly");
+  cleanup();
+}
+
+function checkTools() {
+  let toolsPref = panelWin.document.querySelectorAll("#default-tools-box > checkbox");
+  prefNodes = [];
+  index = 0;
+  for (let tool of toolsPref) {
+    prefNodes.push(tool);
+  }
+  toggleTools();
+}
+
+function toggleTools() {
+  if (index < prefNodes.length) {
+    gDevTools.once("tool-unregistered", checkUnregistered);
+    EventUtils.synthesizeMouse(prefNodes[index], 10, 10, {}, panelWin);
+  }
+  else if (index < 2*prefNodes.length) {
+    gDevTools.once("tool-registered", checkRegistered);
+    EventUtils.synthesizeMouse(prefNodes[index - prefNodes.length], 10, 10, {}, panelWin);
+  }
+  else {
+    cleanup();
+    return;
+  }
+}
+
+function checkUnregistered(event, data) {
+  if (data == prefNodes[index].getAttribute("id")) {
+    ok(true, "Correct tool removed");
+    // checking tab on the toolbox
+    ok(!doc.getElementById("toolbox-tab-" + data), "Tab removed for " + data);
+    index++;
+    toggleTools();
+    return;
+  }
+  ok(false, "Something went wrong, " + data + " was not unregistered");
+  cleanup();
+}
+
+function checkRegistered(event, data) {
+  if (data == prefNodes[index - prefNodes.length].getAttribute("id")) {
+    ok(true, "Correct tool added back");
+    // checking tab on the toolbox
+    ok(doc.getElementById("toolbox-tab-" + data), "Tab added back for " + data);
+    index++;
+    toggleTools();
+    return;
+  }
+  ok(false, "Something went wrong, " + data + " was not registered back");
+  cleanup();
+}
+
+function cleanup() {
+  toolbox.destroy().then(function() {
+    gBrowser.removeCurrentTab();
+    toolbox = doc = prefNodes = prefValues = panelWin = null;
+    finish();
+  });
+}
--- a/browser/devtools/framework/test/head.js
+++ b/browser/devtools/framework/test/head.js
@@ -42,8 +42,34 @@ function addTab(aURL, aCallback)
   return deferred.promise;
 }
 
 registerCleanupFunction(function tearDown() {
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
+
+function synthesizeKeyFromKeyTag(aKeyId, document) {
+  let key = document.getElementById(aKeyId);
+  isnot(key, null, "Successfully retrieved the <key> node");
+
+  let modifiersAttr = key.getAttribute("modifiers");
+
+  let name = null;
+
+  if (key.getAttribute("keycode"))
+    name = key.getAttribute("keycode");
+  else if (key.getAttribute("key"))
+    name = key.getAttribute("key");
+
+  isnot(name, null, "Successfully retrieved keycode/key");
+
+  let modifiers = {
+    shiftKey: modifiersAttr.match("shift"),
+    ctrlKey: modifiersAttr.match("ctrl"),
+    altKey: modifiersAttr.match("alt"),
+    metaKey: modifiersAttr.match("meta"),
+    accelKey: modifiersAttr.match("accel")
+  }
+
+  EventUtils.synthesizeKey(name, modifiers);
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox-options.js
@@ -0,0 +1,105 @@
+
+const { utils: Cu } = Components;
+const DISABLED_TOOLS = "devtools.toolbox.disabledTools";
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/gDevTools.jsm");
+
+window.addEventListener("load", function onLoad() {
+  window.removeEventListener("load", onLoad);
+  setupToolsList();
+  populatePreferences();
+});
+
+function setupToolsList() {
+  let disabledTools = [];
+  try {
+    disabledTools = JSON.parse(Services.prefs.getCharPref(DISABLED_TOOLS));
+  } catch(ex) {
+    Cu.reportError("Error parsing pref " + DISABLED_TOOLS + " as JSON.");
+  }
+  let defaultToolsBox = document.getElementById("default-tools-box");
+  let additionalToolsBox = document.getElementById("additional-tools-box");
+
+  defaultToolsBox.textContent = "";
+  additionalToolsBox.textContent = "";
+
+  let onCheckboxClick = function(id) {
+    if (disabledTools.indexOf(id) > -1) {
+      disabledTools.splice(disabledTools.indexOf(id), 1);
+      Services.prefs.setCharPref(DISABLED_TOOLS, JSON.stringify(disabledTools));
+      gDevTools.emit("tool-registered", id);
+    }
+    else {
+      disabledTools.push(id);
+      Services.prefs.setCharPref(DISABLED_TOOLS, JSON.stringify(disabledTools));
+      gDevTools.emit("tool-unregistered", id);
+    }
+  };
+
+  // Populating the default tools lists
+  for (let tool of gDevTools.getDefaultTools()) {
+    let checkbox = document.createElement("checkbox");
+    checkbox.setAttribute("id", tool.id);
+    checkbox.setAttribute("label", tool.label);
+    checkbox.setAttribute("tooltiptext", tool.tooltip || "");
+    checkbox.setAttribute("checked", disabledTools.indexOf(tool.id) == -1);
+    checkbox.addEventListener("command", onCheckboxClick.bind(null, tool.id));
+    defaultToolsBox.appendChild(checkbox);
+  }
+
+  // Populating the additional tools list that came from add-ons.
+  let atleastOneAddon = false;
+  for (let tool of gDevTools.getAdditionalTools()) {
+    atleastOneAddon = true;
+    let checkbox = document.createElement("checkbox");
+    checkbox.setAttribute("id", tool.id);
+    checkbox.setAttribute("label", tool.label);
+    checkbox.setAttribute("tooltiptext", tool.tooltip || "");
+    checkbox.setAttribute("checked", disabledTools.indexOf(tool.id) == -1);
+    checkbox.addEventListener("command", onCheckboxClick.bind(null, tool.id));
+    additionalToolsBox.appendChild(checkbox);
+  }
+
+  if (!atleastOneAddon) {
+    additionalToolsBox.style.display = "none";
+    additionalToolsBox.previousSibling.style.display = "none";
+  }
+
+  window.focus();
+}
+
+function populatePreferences() {
+  let prefCheckboxes = document.querySelectorAll("checkbox[data-pref]");
+  for (let checkbox of prefCheckboxes) {
+    checkbox.checked = Services.prefs.getBoolPref(checkbox.getAttribute("data-pref"));
+    checkbox.addEventListener("command", function() {
+      let data = {
+        pref: this.getAttribute("data-pref"),
+        newValue: this.checked
+      };
+      data.oldValue = Services.prefs.getBoolPref(data.pref);
+      Services.prefs.setBoolPref(data.pref, data.newValue);
+      gDevTools.emit("pref-changed", data);
+    }.bind(checkbox));
+  }
+  let prefRadiogroups = document.querySelectorAll("radiogroup[data-pref]");
+  for (let radiogroup of prefRadiogroups) {
+    let selectedValue = Services.prefs.getCharPref(radiogroup.getAttribute("data-pref"));
+    for (let radio of radiogroup.childNodes) {
+      radiogroup.selectedIndex = -1;
+      if (radio.getAttribute("value") == selectedValue) {
+        radiogroup.selectedItem = radio;
+        break;
+      }
+    }
+    radiogroup.addEventListener("select", function() {
+      let data = {
+        pref: this.getAttribute("data-pref"),
+        newValue: this.selectedItem.getAttribute("value")
+      };
+      data.oldValue = Services.prefs.getCharPref(data.pref);
+      Services.prefs.setCharPref(data.pref, data.newValue);
+      gDevTools.emit("pref-changed", data);
+    }.bind(radiogroup));
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox-options.xul
@@ -0,0 +1,44 @@
+<?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"?>
+<?xml-stylesheet rel="stylesheet" href="chrome://browser/content/devtools/framework/toolbox.css" type="text/css"?>
+<?xml-stylesheet rel="stylesheet" href="chrome://browser/skin/devtools/toolbox.css" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript;version=1.8" src="toolbox-options.js"></script>
+  <hbox id="options-panel-container" flex="1">
+    <hbox id="options-panel" flex="1">
+      <vbox id="tools-box" class="options-vertical-pane" flex="1">
+        <label value="&options.selectDefaultTools.label;"/>
+        <vbox id="default-tools-box" class="options-groupbox" tabindex="0"/>
+        <label value="&options.selectAdditionalTools.label;"/>
+        <vbox id="additional-tools-box" class="options-groupbox"/>
+      </vbox>
+      <vbox class="options-vertical-pane" flex="1">
+        <label value="&options.selectDevToolsTheme.label;"/>
+        <radiogroup id="devtools-theme-box"
+                    class="options-groupbox"
+                    data-pref="devtools.theme"
+                    orient="horizontal">
+          <radio value="light" label="&options.lightTheme.label;"/>
+          <radio value="dark" label="&options.darkTheme.label;"/>
+        </radiogroup>
+        <label value="&options.context.label;"/>
+        <vbox id="context-options" class="options-groupbox">
+          <checkbox label="&options.enableChrome.label;"
+                    tooltiptext="&options.enableChrome.tooltip;"
+                    data-pref="devtools.chrome.enabled"/>
+          <checkbox label="&options.enableRemote.label;"
+                    tooltiptext="&options.enableRemote.tooltip;"
+                    data-pref="devtools.debugger.remote-enabled"/>
+        </vbox>
+      </vbox>
+    </hbox>
+  </hbox>
+</window>
--- a/browser/devtools/framework/toolbox.css
+++ b/browser/devtools/framework/toolbox.css
@@ -8,8 +8,26 @@
   display: none;
 }
 
 #toolbox-controls > toolbarbutton > .toolbarbutton-text,
 #toolbox-dock-buttons > toolbarbutton > .toolbarbutton-text,
 .command-button > .toolbarbutton-text {
   display: none;
 }
+
+#options-panel-container {
+  overflow: auto;
+}
+
+#options-panel {
+  overflow-y: auto;
+  display: block;
+}
+
+.options-vertical-pane {
+  display: inline;
+  float: left;
+}
+
+.options-vertical-pane > label {
+  display: block;
+}
--- a/browser/devtools/framework/toolbox.xul
+++ b/browser/devtools/framework/toolbox.xul
@@ -13,34 +13,52 @@
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
   <commandset id="editMenuCommands"/>
   <keyset id="editMenuKeys"/>
+  <keyset id="toolbox-keyset">
+    <key id="toolbox-options-key"
+         key="&toolboxOptionsButton.key;"
+         oncommand="void(0);"
+         modifiers="shift, accel"/>
+  </keyset>
 
   <notificationbox id="toolbox-notificationbox" flex="1">
     <toolbar class="devtools-tabbar">
 #ifdef XP_MACOSX
       <hbox id="toolbox-controls">
         <toolbarbutton id="toolbox-close"
                        tooltiptext="&toolboxCloseButton.tooltip;"/>
         <hbox id="toolbox-dock-buttons"/>
       </hbox>
 #endif
+      <toolbarbutton id="toolbox-tab-options"
+                     autocheck="false"
+                     class="command-button toolbox-tab devtools-tab"
+                     tooltiptext="&toolboxOptionsButton.tooltip;"/>
       <hbox id="toolbox-tabs" flex="1">
       </hbox>
       <hbox id="toolbox-buttons" pack="end"/>
 #ifndef XP_MACOSX
       <vbox id="toolbox-controls-separator"/>
       <hbox id="toolbox-controls">
         <hbox id="toolbox-dock-buttons"/>
         <toolbarbutton id="toolbox-close"
                        tooltiptext="&toolboxCloseButton.tooltip;"/>
       </hbox>
 #endif
     </toolbar>
     <deck id="toolbox-deck" flex="1">
+      <vbox id="toolbox-panel-options"
+            class="toolbox-panel">
+        <iframe id="toolbox-panel-iframe-options"
+                class="toolbox-panel-iframe"
+                flex="1" forceOwnRefreshDriver=""
+                src="chrome://browser/content/devtools/framework/toolbox-options.xul">
+        </iframe>
+      </vbox>
     </deck>
   </notificationbox>
 </window>
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -52,15 +52,17 @@ browser.jar:
     content/browser/devtools/profiler/cleopatra/images/circlearrow.svg  (profiler/cleopatra/images/circlearrow.svg)
     content/browser/devtools/profiler/cleopatra/images/noise.png        (profiler/cleopatra/images/noise.png)
     content/browser/devtools/profiler/cleopatra/images/throbber.svg     (profiler/cleopatra/images/throbber.svg)
     content/browser/devtools/profiler/cleopatra/images/treetwisty.svg   (profiler/cleopatra/images/treetwisty.svg)
     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/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)
--- a/browser/devtools/shared/theme-switching.js
+++ b/browser/devtools/shared/theme-switching.js
@@ -1,17 +1,66 @@
 /* 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/. */
 
 (function() {
+  const DEVTOOLS_SKIN_URL = "chrome://browser/skin/devtools/";
+
+  function forceStyle() {
+    let computedStyle = window.getComputedStyle(document.documentElement);
+    if (!computedStyle) {
+      // Null when documentElement is not ready. This method is anyways not
+      // required then as scrollbars would be in their state without flushing.
+      return;
+    }
+    let display = computedStyle.display; // Save display value
+    document.documentElement.style.display = "none";
+    window.getComputedStyle(document.documentElement).display; // Flush
+    document.documentElement.style.display = display; // Restore
+  }
+
+  function switchTheme(theme, old_theme) {
+    let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                         .getInterface(Ci.nsIDOMWindowUtils);
+    if (old_theme && theme != old_theme) {
+      let old_theme_url = Services.io.newURI(DEVTOOLS_SKIN_URL + old_theme +
+                                             "-theme.css", null, null);
+      try {
+        winUtils.removeSheet(old_theme_url, window.AUTHOR_SHEET);
+      } catch(ex) {}
+    }
+    let theme_url = Services.io.newURI(DEVTOOLS_SKIN_URL + theme + "-theme.css",
+                                       null, null);
+    winUtils.loadSheet(theme_url, window.AUTHOR_SHEET);
+    let scrollbar_url =
+      Services.io.newURI(DEVTOOLS_SKIN_URL + "floating-scrollbars-light.css",
+                         null, null);
+    if (theme == "dark") {
+      winUtils.loadSheet(scrollbar_url, window.AGENT_SHEET);
+      forceStyle();
+    }
+    else if (old_theme == "dark") {
+      try {
+        winUtils.removeSheet(scrollbar_url, window.AGENT_SHEET);
+      } catch(ex) {}
+      forceStyle();
+    }
+    document.documentElement.classList.remove("theme-" + old_theme);
+    document.documentElement.classList.add("theme-" + theme);
+  }
+
+  function handlePrefChange(event, data) {
+    if (data.pref == "devtools.theme") {
+        switchTheme(data.newValue, data.oldValue);
+    }
+  }
+
   const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
   Cu.import("resource://gre/modules/Services.jsm");
+  Cu.import("resource:///modules/devtools/gDevTools.jsm");
   let theme = Services.prefs.getCharPref("devtools.theme");
-  let theme_url = Services.io.newURI("chrome://browser/skin/devtools/" + theme + "-theme.css", null, null);
-  let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
-  winUtils.loadSheet(theme_url, window.AUTHOR_SHEET);
-  if (theme == "dark") {
-    let scrollbar_url = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars-light.css", null, null);
-    winUtils.loadSheet(scrollbar_url, window.AGENT_SHEET);
-  }
-  document.documentElement.classList.add("theme-" + theme);
+  switchTheme(theme);
+  gDevTools.on("pref-changed", handlePrefChange);
+  window.addEventListener("unload", function() {
+    gDevTools.off("pref-changed", handlePrefChange);
+  });
 })()
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -112,17 +112,19 @@ SideMenuWidget.prototype = {
 
   /**
    * Removes the specified child node from this container.
    *
    * @param nsIDOMNode aChild
    *        The element associated with the displayed item.
    */
   removeChild: function SMW_removeChild(aChild) {
-    aChild.parentNode.removeChild(aChild);
+    // Remove the item itself, not the contents.
+    let item = aChild.parentNode;
+    item.parentNode.removeChild(item);
     this._orderedMenuElementsArray.splice(
       this._orderedMenuElementsArray.indexOf(aChild), 1);
 
     if (this._selectedItem == aChild) {
       this._selectedItem = null;
     }
   },
 
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -85,17 +85,16 @@
   -  in the source editor's context menu for the global search operation. -->
 <!ENTITY debuggerUI.searchGlobal        "Search in all files">
 <!ENTITY debuggerUI.searchGlobal.key    "F">
 
 <!-- LOCALIZATION NOTE (debuggerUI.searchFunction): This is the text that appears
   -  in the source editor's context menu for the function search operation. -->
 <!ENTITY debuggerUI.searchFunction      "Search for function definition">
 <!ENTITY debuggerUI.searchFunction.key  "D">
-<!ENTITY debuggerUI.searchFunction.altkey "O">
 
 <!-- LOCALIZATION NOTE (debuggerUI.searchToken): This is the text that appears
   -  in the source editor's context menu for the token search operation. -->
 <!ENTITY debuggerUI.searchToken         "Find">
 <!ENTITY debuggerUI.searchToken.key     "F">
 
 <!-- LOCALIZATION NOTE (debuggerUI.searchLine): This is the text that appears
   -  in the source editor's context menu for the line search operation. -->
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties
@@ -538,16 +538,38 @@ addonListTypeDesc=Select an add-on type
 addonListDictionaryHeading=The following dictionaries are currently installed:
 addonListExtensionHeading=The following extensions are currently installed:
 addonListLocaleHeading=The following locales are currently installed:
 addonListPluginHeading=The following plugins are currently installed:
 addonListThemeHeading=The following themes are currently installed:
 addonListAllHeading=The following add-ons are currently installed:
 addonListUnknownHeading=The following add-ons of the selected type are currently installed:
 
+# LOCALIZATION NOTE (addonListOutEnable, addonListOutDisable) Used in the
+# output of the 'addon list' command as the labels for the enable/disable
+# action buttons in the listing. This string is designed to be shown in a
+# small action button next to the addon name, which is why it should be as
+# short as possible.
+addonListOutEnable=Enable
+addonListOutDisable=Disable
+
+# LOCALIZATION NOTE (addonPending, addonPendingEnable, addonPendingDisable,
+# addonPendingUninstall, addonPendingInstall, addonPendingUpgrade) Used in
+# the output of the 'addon list' command as the descriptions of pending
+# addon operations. addonPending is used as a prefix for a list of pending
+# actions (named by the other lookup variables). These strings are designed
+# to be shown alongside addon names, which is why they should be as short
+# as possible.
+addonPending=pending
+addonPendingEnable=enable
+addonPendingDisable=disable
+addonPendingUninstall=uninstall
+addonPendingInstall=install
+addonPendingUpgrade=upgrade
+
 # LOCALIZATION NOTE (addonNameDesc) A very short description of the
 # name parameter of numerous add-on commands. This string is designed to be shown
 # in a menu alongside the command name, which is why it should be as short as
 # possible.
 addonNameDesc=The name of the add-on
 
 # LOCALIZATION NOTE (addonNoneOfType) Used in the output of the 'addon list'
 # command when a search for add-ons of a particular type were not found.
--- a/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/toolbox.dtd
@@ -1,7 +1,47 @@
 <!-- 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/. -->
 
+<!-- LOCALIZATION NOTE : FILE This file contains the Toolbox strings -->
+<!-- LOCALIZATION NOTE : FILE Do not translate key -->
+
 <!ENTITY closeCmd.key  "W">
 
-<!ENTITY toolboxCloseButton.tooltip  "Close Developer Tools">
+<!ENTITY toolboxCloseButton.tooltip    "Close Developer Tools">
+<!ENTITY toolboxOptionsButton.tooltip  "Toggle Options Panel">
+<!ENTITY toolboxOptionsButton.key      "O">
+
+<!-- LOCALIZATION NOTE (options.context.label): This is the label for the
+  -  heading of the group of two about:config preferences to toggle chrome
+  -  and remote debugging in the options panel. -->
+<!ENTITY options.context.label         "Advanced settings (requires a browser restart)">
+
+<!-- LOCALIZATION NOTE (options.enableChrome.label): This is the label for the
+  -  checkbox that toggles chrome debugging, i.e. devtools.chrome.enabled
+  -  boolean preference in about:config, in the options panel. -->
+<!ENTITY options.enableChrome.label    "Enable chrome debugging">
+<!ENTITY options.enableChrome.tooltip  "Turning this option on will allow you to use various developer tools in browser context">
+
+<!-- LOCALIZATION NOTE (options.enableRemote.label): This is the label for the
+  -  checkbox that toggles remote debugging, i.e. devtools.debugger.remote-enabled
+  -  boolean preference in about:config, in the options panel. -->
+<!ENTITY options.enableRemote.label    "Enable remote debugging">
+<!ENTITY options.enableRemote.tooltip  "Turning this option on will allow the developer tools to debug remote Firefox instance like Firefox OS">
+
+<!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
+  -  the heading of group of checkboxes corresponding to the default developer
+  -  tools. -->
+<!ENTITY options.selectDefaultTools.label     "Default Firefox Developer Tools">
+
+<!-- LOCALIZATION NOTE (options.selectDefaultTools.label): This is the label for
+  -  the heading of group of checkboxes corresponding to the developer tools
+  -  added by add-ons. This heading is hidden when there is no developer tool
+  -  installed by add-ons. -->
+<!ENTITY options.selectAdditionalTools.label  "Developer Tools installed by add-ons">
+
+<!-- LOCALIZATION NOTE (options.selectDevToolsTheme.label): This is the label for
+  -  the heading of the radiobox corresponding to the theme of the developer
+  -  tools. -->
+<!ENTITY options.selectDevToolsTheme.label   "Choose DevTools theme:">
+<!ENTITY options.darkTheme.label             "Dark theme">
+<!ENTITY options.lightTheme.label            "Light theme">
new file mode 100644
index 0000000000000000000000000000000000000000..e937b600b7bca4a2dc614180af6dfc6a35a575d8
GIT binary patch
literal 707
zc$@*l0zCbRP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ50000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!Wl2OqRCwCNR7+?RQ4~G%Gt(r~L>D&V
zk2Da8;xZtDA_Z-#CA*N7B^yOz*5XERA+D5^P*brWx=~`37Od5kC?dELtgUgA2E>08
zLYt<UNis9OOq(!CCR11XhRb{J^3FYT&%InqRaN|t#cu8#G3GBZGO?QOz9lxDPP5Kk
zo>8k^7_Cau;?R-9H=4xE_JMuRWm!I97Jy-xSH)jnMmmVM#0r9d2kGgW&1UCb%+8!6
zE}m_rL4dA3ZdfclKvC^TQVvNH@$+lWFt{03k!3_8V{kZ}+`@<V^VhCi`rLr9`bV~Y
zC-^?AaZM`grurLU8~x+nzZWM@4P$j>1=p`$en{NkiAin53{7ihD02^gQ<3O}^YHuq
z$Yz%iA5Uy#t}2L(oz<S)O58-Tkbg&xKN=agMWab@GwaDqzNy=jSSyv_@eJblv7>}j
z#_5q^47gla{5X%NGf&|4db8xYsByIuQ=l2z*l5Z`XbNRgisZz&b_)iBICSs;0)YS&
zMZwgaNfLuYEEX$j|JhAUx8&|Lvy3SstJNl8Veu2*zIhFv=Mjxw)G*VJA7Od90E%W1
z3We$|uFe3xWTq&}w7Ix#76^_VxPR|1N~KlJSIFlvH#dtudw&<cjaU-bAy&$eh-`Y(
ze4=?*SEb6vUXzhb#I<vBA`V5Rw0d``v^g^Qox2C0iIOyA7M!<OUjF{Jbf(!LO}8Ga
zlA6l(DygkZ>dJy)Ig%~i!jjBIJ#k~~*>xkd*J{*g&0u7<u$fGTO{G#oE|;^p-R^QY
p94`5MzIqc&h--S{f4=?*FaVhN?&ckjhavy~002ovPDHLkV1nH>N1Xrw
new file mode 100644
index 0000000000000000000000000000000000000000..00d6d450c13ce88f9013d62efcabb6d04c597800
GIT binary patch
literal 700
zc$@*e0z>_YP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ500006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-2@5?4>2NI5a9p-0!c|k
zK~y-)y_CC8Q*ji>Kj+@tHes;~tpcGUAdx@^*=V{6k%GdgAov0#`WL91&s9OAF-AlO
z6?`Fynh1XY11*ghn}}ed=mvv4dfVQ69a^eLDVQ{#;WwP*bH2ax6w9*spLYCcyA_@c
zA?>Y)tnu-2>~?!rKt#}WojsM6JbN)Ls;UCe(RO%KUPOq;<0KLZoX%}jReRBFHam6o
z^|ZEi5Rb<|00b;ZK7uIVusaxh{D`k}-_``R+3f7AtE2Tuibv8R1VI!9%QWe~cbD*F
zh#dum^bb4~4S`~hhgx6lrez9FOfdK3`#OKI$Ai!3+mP$)>m?S8(GX}N68Q*#f(52w
zY^gu0re^eK<L}(Q#q*&joIQ7*oh2n{zw$4GVQt(*0OsfCiAJMo_p9NTJQ%pou@hZX
zReO^$Qp2p|Vp1*BBoc{m<<bR4Muq_hg@W9?(aYYN8k$>L(xQ@Lv|I?ArpcGt8Q#8m
z&4;Ne^7CCh9U3GW)#>ayh12O=$K*s<(=_%s1el$jq3`-Nu3o;#!omVw-91!$y&0L@
zlseV?hCm~3_jcZg!<3irCJ<;uL^6LiH}@#1>~gs|(A<owsq~yaLt#<T##IuLO|RCf
zIUJ648T`rT<>hg*vzx}IgH%*hWaL*jK+|=d(b0GOTwKC15?OXwV=@@T{Oh*sy3W|x
zD2q$W7>0qOD2ND#Y5eX%iVp`vtVCCm!al#B>FG}_uPkRzHx{F`tc-%fqBU9j{C=iC
iZ;jtoR*K8z2H+P+JJjoX``DuZ0000<MNUMnLSTYIu0whN
--- a/browser/themes/linux/devtools/dark-theme.css
+++ b/browser/themes/linux/devtools/dark-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(255,255,255,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") 14px 0;
 }
 
 .theme-selected {
   background: #26384E;
 }
 
 .theme-bg-darker {
   background-color: rgba(0,0,0,0.1);
--- a/browser/themes/linux/devtools/light-theme.css
+++ b/browser/themes/linux/devtools/light-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(0,0,0,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") 14px 0;
 }
 
 .theme-selected {
   background-color: hsl(0,0%,90%);
 }
 
 .theme-bg-darker {
   background: #F9F9F9;
--- a/browser/themes/linux/devtools/toolbox.css
+++ b/browser/themes/linux/devtools/toolbox.css
@@ -123,16 +123,29 @@
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
+#toolbox-tab-options {
+  list-style-image: url("chrome://browser/skin/devtools/option-icon.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+}
+
+#toolbox-tab-options[checked=true] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
+#toolbox-tab-options > image {
+  opacity: 1;
+  -moz-margin-start: 0;
+}
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
   background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border-color: #060a0d;
@@ -219,8 +232,33 @@
   background-repeat: no-repeat,
                      no-repeat,
                      no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: top right, top left, left, right;
   box-shadow: 1px -1px 0 hsla(206,37%,4%,.2) inset;
 }
+
+#options-panel {
+  background-image: url("chrome://browser/skin/newtab/noise.png");
+}
+
+.options-vertical-pane {
+  margin: 15px;
+  width: calc(50% - 30px);
+  min-width: 400px;
+  -moz-padding-start: 5px;
+}
+
+.options-vertical-pane > label {
+  padding: 5px 0;
+  font-size: 1.4rem;
+}
+
+.options-groupbox {
+  -moz-margin-start: 15px;
+  padding: 4px;
+}
+
+.options-groupbox > * {
+  padding: 2px;
+}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -126,16 +126,18 @@ browser.jar:
   skin/classic/browser/devtools/command-scratchpad.png (devtools/command-scratchpad.png)
   skin/classic/browser/devtools/command-tilt.png      (devtools/command-tilt.png)
   skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
   skin/classic/browser/devtools/goto-mdn.png          (devtools/goto-mdn.png)
   skin/classic/browser/devtools/ruleview.css          (devtools/ruleview.css)
   skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
+  skin/classic/browser/devtools/checkbox-dark.png     (devtools/checkbox-dark.png)
+  skin/classic/browser/devtools/checkbox-light.png    (devtools/checkbox-light.png)
   skin/classic/browser/devtools/commandline.css              (devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css      (devtools/markup-view.css)
   skin/classic/browser/devtools/orion.css             (devtools/orion.css)
   skin/classic/browser/devtools/orion-container.css   (devtools/orion-container.css)
   skin/classic/browser/devtools/orion-task.png        (devtools/orion-task.png)
   skin/classic/browser/devtools/orion-breakpoint.png  (devtools/orion-breakpoint.png)
   skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
   skin/classic/browser/devtools/breadcrumbs-scrollbutton.png                 (devtools/breadcrumbs-scrollbutton.png)
new file mode 100644
index 0000000000000000000000000000000000000000..e937b600b7bca4a2dc614180af6dfc6a35a575d8
GIT binary patch
literal 707
zc$@*l0zCbRP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ50000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!Wl2OqRCwCNR7+?RQ4~G%Gt(r~L>D&V
zk2Da8;xZtDA_Z-#CA*N7B^yOz*5XERA+D5^P*brWx=~`37Od5kC?dELtgUgA2E>08
zLYt<UNis9OOq(!CCR11XhRb{J^3FYT&%InqRaN|t#cu8#G3GBZGO?QOz9lxDPP5Kk
zo>8k^7_Cau;?R-9H=4xE_JMuRWm!I97Jy-xSH)jnMmmVM#0r9d2kGgW&1UCb%+8!6
zE}m_rL4dA3ZdfclKvC^TQVvNH@$+lWFt{03k!3_8V{kZ}+`@<V^VhCi`rLr9`bV~Y
zC-^?AaZM`grurLU8~x+nzZWM@4P$j>1=p`$en{NkiAin53{7ihD02^gQ<3O}^YHuq
z$Yz%iA5Uy#t}2L(oz<S)O58-Tkbg&xKN=agMWab@GwaDqzNy=jSSyv_@eJblv7>}j
z#_5q^47gla{5X%NGf&|4db8xYsByIuQ=l2z*l5Z`XbNRgisZz&b_)iBICSs;0)YS&
zMZwgaNfLuYEEX$j|JhAUx8&|Lvy3SstJNl8Veu2*zIhFv=Mjxw)G*VJA7Od90E%W1
z3We$|uFe3xWTq&}w7Ix#76^_VxPR|1N~KlJSIFlvH#dtudw&<cjaU-bAy&$eh-`Y(
ze4=?*SEb6vUXzhb#I<vBA`V5Rw0d``v^g^Qox2C0iIOyA7M!<OUjF{Jbf(!LO}8Ga
zlA6l(DygkZ>dJy)Ig%~i!jjBIJ#k~~*>xkd*J{*g&0u7<u$fGTO{G#oE|;^p-R^QY
p94`5MzIqc&h--S{f4=?*FaVhN?&ckjhavy~002ovPDHLkV1nH>N1Xrw
new file mode 100644
index 0000000000000000000000000000000000000000..00d6d450c13ce88f9013d62efcabb6d04c597800
GIT binary patch
literal 700
zc$@*e0z>_YP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ500006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-2@5?4>2NI5a9p-0!c|k
zK~y-)y_CC8Q*ji>Kj+@tHes;~tpcGUAdx@^*=V{6k%GdgAov0#`WL91&s9OAF-AlO
z6?`Fynh1XY11*ghn}}ed=mvv4dfVQ69a^eLDVQ{#;WwP*bH2ax6w9*spLYCcyA_@c
zA?>Y)tnu-2>~?!rKt#}WojsM6JbN)Ls;UCe(RO%KUPOq;<0KLZoX%}jReRBFHam6o
z^|ZEi5Rb<|00b;ZK7uIVusaxh{D`k}-_``R+3f7AtE2Tuibv8R1VI!9%QWe~cbD*F
zh#dum^bb4~4S`~hhgx6lrez9FOfdK3`#OKI$Ai!3+mP$)>m?S8(GX}N68Q*#f(52w
zY^gu0re^eK<L}(Q#q*&joIQ7*oh2n{zw$4GVQt(*0OsfCiAJMo_p9NTJQ%pou@hZX
zReO^$Qp2p|Vp1*BBoc{m<<bR4Muq_hg@W9?(aYYN8k$>L(xQ@Lv|I?ArpcGt8Q#8m
z&4;Ne^7CCh9U3GW)#>ayh12O=$K*s<(=_%s1el$jq3`-Nu3o;#!omVw-91!$y&0L@
zlseV?hCm~3_jcZg!<3irCJ<;uL^6LiH}@#1>~gs|(A<owsq~yaLt#<T##IuLO|RCf
zIUJ648T`rT<>hg*vzx}IgH%*hWaL*jK+|=d(b0GOTwKC15?OXwV=@@T{Oh*sy3W|x
zD2q$W7>0qOD2ND#Y5eX%iVp`vtVCCm!al#B>FG}_uPkRzHx{F`tc-%fqBU9j{C=iC
iZ;jtoR*K8z2H+P+JJjoX``DuZ0000<MNUMnLSTYIu0whN
--- a/browser/themes/osx/devtools/dark-theme.css
+++ b/browser/themes/osx/devtools/dark-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(255,255,255,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") 14px 0;
 }
 
 .theme-selected {
   background: #26384E;
 }
 
 .theme-bg-darker {
   background-color: rgba(0,0,0,0.1);
--- a/browser/themes/osx/devtools/light-theme.css
+++ b/browser/themes/osx/devtools/light-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(0,0,0,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") 14px 0;
 }
 
 .theme-selected {
   background-color: hsl(0,0%,90%);
 }
 
 .theme-bg-darker {
   background: #F9F9F9;
--- a/browser/themes/osx/devtools/toolbox.css
+++ b/browser/themes/osx/devtools/toolbox.css
@@ -111,16 +111,30 @@
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
+#toolbox-tab-options {
+  list-style-image: url("chrome://browser/skin/devtools/option-icon.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+  border-left: 1px solid hsla(206,37%,4%,.45);
+}
+
+#toolbox-tab-options[checked=true] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
+#toolbox-tab-options > image {
+  opacity: 1;
+  -moz-margin-start: 0;
+}
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
   background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border-color: #060a0d;
@@ -129,17 +143,16 @@
   box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset,
               0 -1px 0 hsla(206,37%,4%,.1) inset;
   min-height: 32px;
   padding: 0;
 }
 
 #toolbox-tabs {
   margin: 0;
-  border-left: 1px solid hsla(206,37%,4%,.45);
 }
 
 .devtools-tab {
   -moz-appearance: none;
   min-width: 32px;
   min-height: 32px;
   max-width: 110px;
   color: #b6babf;
@@ -206,8 +219,33 @@
   background-repeat: no-repeat,
                      no-repeat,
                      no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: top right, top left, left, right;
   box-shadow: 1px -1px 0 hsla(206,37%,4%,.2) inset;
 }
+
+#options-panel {
+  background-image: url("chrome://browser/skin/newtab/noise.png");
+}
+
+.options-vertical-pane {
+  margin: 15px;
+  width: calc(50% - 30px);
+  min-width: 400px;
+  -moz-padding-start: 5px;
+}
+
+.options-vertical-pane > label {
+  padding: 5px 0;
+  font-size: 1.4rem;
+}
+
+.options-groupbox {
+  -moz-margin-start: 15px;
+  padding: 4px;
+}
+
+.options-groupbox > * {
+  padding: 2px;
+}
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -211,16 +211,18 @@ browser.jar:
   skin/classic/browser/devtools/command-paintflashing.png   (devtools/command-paintflashing.png)
   skin/classic/browser/devtools/command-responsivemode.png  (devtools/command-responsivemode.png)
   skin/classic/browser/devtools/command-scratchpad.png      (devtools/command-scratchpad.png)
   skin/classic/browser/devtools/command-tilt.png            (devtools/command-tilt.png)
   skin/classic/browser/devtools/alerticon-warning.png       (devtools/alerticon-warning.png)
   skin/classic/browser/devtools/goto-mdn.png                (devtools/goto-mdn.png)
   skin/classic/browser/devtools/ruleview.css                (devtools/ruleview.css)
   skin/classic/browser/devtools/commandline.css             (devtools/commandline.css)
+  skin/classic/browser/devtools/checkbox-dark.png           (devtools/checkbox-dark.png)
+  skin/classic/browser/devtools/checkbox-light.png          (devtools/checkbox-light.png)
   skin/classic/browser/devtools/markup-view.css             (devtools/markup-view.css)
   skin/classic/browser/devtools/orion.css                   (devtools/orion.css)
   skin/classic/browser/devtools/orion-container.css         (devtools/orion-container.css)
   skin/classic/browser/devtools/orion-task.png              (devtools/orion-task.png)
   skin/classic/browser/devtools/orion-breakpoint.png        (devtools/orion-breakpoint.png)
   skin/classic/browser/devtools/orion-debug-location.png    (devtools/orion-debug-location.png)
   skin/classic/browser/devtools/toolbarbutton-close.png     (devtools/toolbarbutton-close.png)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
new file mode 100644
index 0000000000000000000000000000000000000000..e937b600b7bca4a2dc614180af6dfc6a35a575d8
GIT binary patch
literal 707
zc$@*l0zCbRP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ50000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!Wl2OqRCwCNR7+?RQ4~G%Gt(r~L>D&V
zk2Da8;xZtDA_Z-#CA*N7B^yOz*5XERA+D5^P*brWx=~`37Od5kC?dELtgUgA2E>08
zLYt<UNis9OOq(!CCR11XhRb{J^3FYT&%InqRaN|t#cu8#G3GBZGO?QOz9lxDPP5Kk
zo>8k^7_Cau;?R-9H=4xE_JMuRWm!I97Jy-xSH)jnMmmVM#0r9d2kGgW&1UCb%+8!6
zE}m_rL4dA3ZdfclKvC^TQVvNH@$+lWFt{03k!3_8V{kZ}+`@<V^VhCi`rLr9`bV~Y
zC-^?AaZM`grurLU8~x+nzZWM@4P$j>1=p`$en{NkiAin53{7ihD02^gQ<3O}^YHuq
z$Yz%iA5Uy#t}2L(oz<S)O58-Tkbg&xKN=agMWab@GwaDqzNy=jSSyv_@eJblv7>}j
z#_5q^47gla{5X%NGf&|4db8xYsByIuQ=l2z*l5Z`XbNRgisZz&b_)iBICSs;0)YS&
zMZwgaNfLuYEEX$j|JhAUx8&|Lvy3SstJNl8Veu2*zIhFv=Mjxw)G*VJA7Od90E%W1
z3We$|uFe3xWTq&}w7Ix#76^_VxPR|1N~KlJSIFlvH#dtudw&<cjaU-bAy&$eh-`Y(
ze4=?*SEb6vUXzhb#I<vBA`V5Rw0d``v^g^Qox2C0iIOyA7M!<OUjF{Jbf(!LO}8Ga
zlA6l(DygkZ>dJy)Ig%~i!jjBIJ#k~~*>xkd*J{*g&0u7<u$fGTO{G#oE|;^p-R^QY
p94`5MzIqc&h--S{f4=?*FaVhN?&ckjhavy~002ovPDHLkV1nH>N1Xrw
new file mode 100644
index 0000000000000000000000000000000000000000..00d6d450c13ce88f9013d62efcabb6d04c597800
GIT binary patch
literal 700
zc$@*e0z>_YP)<h;3K|Lk000e1NJLTq0015U000gM1^@s6IOeQ500006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-2@5?4>2NI5a9p-0!c|k
zK~y-)y_CC8Q*ji>Kj+@tHes;~tpcGUAdx@^*=V{6k%GdgAov0#`WL91&s9OAF-AlO
z6?`Fynh1XY11*ghn}}ed=mvv4dfVQ69a^eLDVQ{#;WwP*bH2ax6w9*spLYCcyA_@c
zA?>Y)tnu-2>~?!rKt#}WojsM6JbN)Ls;UCe(RO%KUPOq;<0KLZoX%}jReRBFHam6o
z^|ZEi5Rb<|00b;ZK7uIVusaxh{D`k}-_``R+3f7AtE2Tuibv8R1VI!9%QWe~cbD*F
zh#dum^bb4~4S`~hhgx6lrez9FOfdK3`#OKI$Ai!3+mP$)>m?S8(GX}N68Q*#f(52w
zY^gu0re^eK<L}(Q#q*&joIQ7*oh2n{zw$4GVQt(*0OsfCiAJMo_p9NTJQ%pou@hZX
zReO^$Qp2p|Vp1*BBoc{m<<bR4Muq_hg@W9?(aYYN8k$>L(xQ@Lv|I?ArpcGt8Q#8m
z&4;Ne^7CCh9U3GW)#>ayh12O=$K*s<(=_%s1el$jq3`-Nu3o;#!omVw-91!$y&0L@
zlseV?hCm~3_jcZg!<3irCJ<;uL^6LiH}@#1>~gs|(A<owsq~yaLt#<T##IuLO|RCf
zIUJ648T`rT<>hg*vzx}IgH%*hWaL*jK+|=d(b0GOTwKC15?OXwV=@@T{Oh*sy3W|x
zD2q$W7>0qOD2ND#Y5eX%iVp`vtVCCm!al#B>FG}_uPkRzHx{F`tc-%fqBU9j{C=iC
iZ;jtoR*K8z2H+P+JJjoX``DuZ0000<MNUMnLSTYIu0whN
--- a/browser/themes/windows/devtools/dark-theme.css
+++ b/browser/themes/windows/devtools/dark-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(255,255,255,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-dark.png") 14px 0;
 }
 
 .theme-selected {
   background: #26384E;
 }
 
 .theme-bg-darker {
   background-color: rgba(0,0,0,0.1);
--- a/browser/themes/windows/devtools/light-theme.css
+++ b/browser/themes/windows/devtools/light-theme.css
@@ -32,29 +32,26 @@
 .theme-twisty[open] {
   width: 10px;
   height: 10px;
   background-image: linear-gradient(to bottom right, transparent 68%,  rgba(0,0,0,0.5) 68%);
 }
 
 .theme-checkbox {
   display: inline-block;
-  border: 1px solid rgba(160,160,160,0.4);
-  width: 6px;
-  height: 6px;
-  padding: 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
+  border: 0;
+  width: 14px;
+  height: 14px;
+  padding: 0;
   outline: none;
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") no-repeat;
 }
 
 .theme-checkbox[checked] {
-  background-clip: content-box;
-  background-image: linear-gradient(to bottom right, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%),
-                    linear-gradient(to bottom left, transparent 48%, rgba(160,160,160,1) 48%, rgba(160,160,160,1) 52%, transparent 52%);
+  background: url("chrome://browser/skin/devtools/checkbox-light.png") 14px 0;
 }
 
 .theme-selected {
   background-color: hsl(0,0%,90%);
 }
 
 .theme-bg-darker {
   background: #F9F9F9;
--- a/browser/themes/windows/devtools/toolbox.css
+++ b/browser/themes/windows/devtools/toolbox.css
@@ -126,16 +126,29 @@
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
+#toolbox-tab-options {
+  list-style-image: url("chrome://browser/skin/devtools/option-icon.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+}
+
+#toolbox-tab-options[checked=true] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
+#toolbox-tab-options > image {
+  opacity: 1;
+  -moz-margin-start: 0;
+}
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
   background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border-bottom: 1px solid #060a0d;
@@ -215,8 +228,33 @@
   background-repeat: no-repeat,
                      no-repeat,
                      no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: top right, top left, left, right;
   box-shadow: 1px -1px 0 hsla(206,37%,4%,.2) inset;
 }
+
+#options-panel {
+  background-image: url("chrome://browser/skin/newtab/noise.png");
+}
+
+.options-vertical-pane {
+  margin: 15px;
+  width: calc(50% - 30px);
+  min-width: 400px;
+  -moz-padding-start: 5px;
+}
+
+.options-vertical-pane > label {
+  padding: 5px 0;
+  font-size: 1.4rem;
+}
+
+.options-groupbox {
+  -moz-margin-start: 15px;
+  padding: 4px;
+}
+
+.options-groupbox > * {
+  padding: 2px;
+}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -151,16 +151,18 @@ browser.jar:
         skin/classic/browser/devtools/alerticon-warning.png         (devtools/alerticon-warning.png)
         skin/classic/browser/devtools/goto-mdn.png                  (devtools/goto-mdn.png)
         skin/classic/browser/devtools/ruleview.css                  (devtools/ruleview.css)
         skin/classic/browser/devtools/commandline.css               (devtools/commandline.css)
         skin/classic/browser/devtools/command-paintflashing.png     (devtools/command-paintflashing.png)
         skin/classic/browser/devtools/command-responsivemode.png    (devtools/command-responsivemode.png)
         skin/classic/browser/devtools/command-scratchpad.png        (devtools/command-scratchpad.png)
         skin/classic/browser/devtools/command-tilt.png              (devtools/command-tilt.png)
+        skin/classic/browser/devtools/checkbox-dark.png             (devtools/checkbox-dark.png)
+        skin/classic/browser/devtools/checkbox-light.png            (devtools/checkbox-light.png)
         skin/classic/browser/devtools/markup-view.css               (devtools/markup-view.css)
         skin/classic/browser/devtools/orion.css                     (devtools/orion.css)
         skin/classic/browser/devtools/orion-container.css           (devtools/orion-container.css)
         skin/classic/browser/devtools/orion-task.png                (devtools/orion-task.png)
         skin/classic/browser/devtools/orion-breakpoint.png          (devtools/orion-breakpoint.png)
         skin/classic/browser/devtools/orion-debug-location.png      (devtools/orion-debug-location.png)
         skin/classic/browser/devtools/toolbarbutton-close.png       (devtools/toolbarbutton-close.png)
         skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
@@ -391,16 +393,18 @@ browser.jar:
         skin/classic/aero/browser/devtools/light-theme.css           (devtools/light-theme.css)
         skin/classic/aero/browser/devtools/widgets.css               (devtools/widgets.css)
         skin/classic/aero/browser/devtools/arrows.png                (devtools/arrows.png)
         skin/classic/aero/browser/devtools/commandline.png           (devtools/commandline.png)
         skin/classic/aero/browser/devtools/command-paintflashing.png  (devtools/command-paintflashing.png)
         skin/classic/aero/browser/devtools/command-responsivemode.png (devtools/command-responsivemode.png)
         skin/classic/aero/browser/devtools/command-scratchpad.png    (devtools/command-scratchpad.png)
         skin/classic/aero/browser/devtools/command-tilt.png          (devtools/command-tilt.png)
+        skin/classic/aero/browser/devtools/checkbox-dark.png         (devtools/checkbox-dark.png)
+        skin/classic/aero/browser/devtools/checkbox-light.png        (devtools/checkbox-light.png)
         skin/classic/aero/browser/devtools/alerticon-warning.png     (devtools/alerticon-warning.png)
         skin/classic/aero/browser/devtools/goto-mdn.png              (devtools/goto-mdn.png)
         skin/classic/aero/browser/devtools/ruleview.css              (devtools/ruleview.css)
         skin/classic/aero/browser/devtools/commandline.css           (devtools/commandline.css)
         skin/classic/aero/browser/devtools/markup-view.css           (devtools/markup-view.css)
         skin/classic/aero/browser/devtools/orion.css                 (devtools/orion.css)
         skin/classic/aero/browser/devtools/orion-container.css       (devtools/orion-container.css)
         skin/classic/aero/browser/devtools/orion-task.png            (devtools/orion-task.png)
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -488,17 +488,17 @@ ThreadActor.prototype = {
       let promise = this.sources.getOriginalLocation(form.where.url,
                                                      form.where.line)
         .then(function (aOrigLocation) {
           form.where = aOrigLocation;
         });
       promises.push(promise);
     }
 
-    return resolveAll(promises).then(function () {
+    return all(promises).then(function () {
       return { frames: frames };
     });
   },
 
   onReleaseMany: function TA_onReleaseMany(aRequest) {
     if (!aRequest.actors) {
       return { error: "missingParameter",
                message: "no actors were specified" };
@@ -557,17 +557,17 @@ ThreadActor.prototype = {
 
       let response = this._setBreakpoint(aLocation);
       // If the original location of our generated location is different from
       // the original location we attempted to set the breakpoint on, we will
       // need to know so that we can set actualLocation on the response.
       let originalLocation = this.sources.getOriginalLocation(aLocation.url,
                                                               aLocation.line);
 
-      return resolveAll([response, originalLocation])
+      return all([response, originalLocation])
         .then(([aResponse, {url, line}]) => {
           if (aResponse.actualLocation) {
             let actualOrigLocation = this.sources.getOriginalLocation(
               aResponse.actualLocation.url, aResponse.actualLocation.line);
             return actualOrigLocation.then(function ({ url, line }) {
               if (url !== originalSource || line !== originalLine) {
                 aResponse.actualLocation = { url: url, line: line };
               }
@@ -687,18 +687,18 @@ ThreadActor.prototype = {
       actor: actor.actorID
     };
   },
 
   /**
    * Get the script and source lists from the debugger.
    */
   _discoverScriptsAndSources: function TA__discoverScriptsAndSources() {
-    return resolveAll([this._addScript(s)
-                       for (s of this.dbg.findScripts())]);
+    return all([this._addScript(s)
+                for (s of this.dbg.findScripts())]);
   },
 
   onSources: function TA_onSources(aRequest) {
     return this._discoverScriptsAndSources().then(() => {
       return {
         sources: [s.form() for (s of this.sources.iter())]
       };
     });
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -20,21 +20,17 @@ const DBG_STRINGS_URI = "chrome://global
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 
 Cu.import("resource://gre/modules/jsdebugger.jsm");
 addDebuggerToGlobal(this);
 
 Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
-const { defer, resolve, reject } = Promise;
-let promisedArray = Promise.promised(Array);
-function resolveAll(aPromises) {
-  return promisedArray.apply(null, aPromises);
-};
+const { defer, resolve, reject, all } = Promise;
 
 Cu.import("resource://gre/modules/devtools/SourceMap.jsm");
 
 function dumpn(str) {
   if (wantLogging) {
     dump("DBG-SERVER: " + str + "\n");
   }
 }