Bug 1248603 - Register devtools menuitems dynamically. r=gijs,jryans
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 01 Apr 2016 05:49:00 -0700
changeset 329202 9b9b8514c6b0479d470b0c30f84b6e9552591da5
parent 329201 0b016f319532937405bf971cdb1e426e81bc35f5
child 329203 97e1c3fdf6f22c4a643b378eec2b775d9d95bb3d
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs, jryans
bugs1248603
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1248603 - Register devtools menuitems dynamically. r=gijs,jryans
browser/base/content/browser-menubar.inc
browser/base/content/browser-sets.inc
browser/locales/en-US/chrome/browser/browser.dtd
devtools/client/framework/browser-menus.js
devtools/client/framework/devtools-browser.js
devtools/client/locales/en-US/menus.properties
devtools/client/menus.js
devtools/client/moz.build
devtools/client/responsivedesign/responsivedesign.jsm
devtools/client/responsivedesign/test/browser_responsiveruleview.js
devtools/client/responsivedesign/test/browser_responsiveui.js
devtools/client/responsivedesign/test/head.js
devtools/client/shared/developer-toolbar.js
devtools/client/shared/test/browser_toolbar_basic.js
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -515,59 +515,19 @@
                         accesskey="&syncReAuthItem.accesskey;"
                         observes="sync-reauth-state"
                         oncommand="gSyncUI.openSignInAgainPage('menubar');"/>
               <menuseparator id="devToolsSeparator"/>
               <menu id="webDeveloperMenu"
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
                 <menupopup id="menuWebDeveloperPopup">
-                  <menuitem id="menu_devToolbox"
-                            observes="devtoolsMenuBroadcaster_DevToolbox"
-                            accesskey="&devToolboxMenuItem.accesskey;"/>
-                  <menuseparator id="menu_devtools_separator"/>
-                  <menuitem id="menu_devToolbar"
-                            observes="devtoolsMenuBroadcaster_DevToolbar"
-                            accesskey="&devToolbarMenu.accesskey;"/>
-                  <menuitem id="menu_webide"
-                            observes="devtoolsMenuBroadcaster_webide"
-                            accesskey="&webide.accesskey;"/>
-                  <menuitem id="menu_browserToolbox"
-                            observes="devtoolsMenuBroadcaster_BrowserToolbox"
-                            accesskey="&browserToolboxMenu.accesskey;"/>
-                  <menuitem id="menu_browserContentToolbox"
-                            observes="devtoolsMenuBroadcaster_BrowserContentToolbox"
-                            accesskey="&browserContentToolboxMenu.accesskey;" />
-                  <menuitem id="menu_browserConsole"
-                            observes="devtoolsMenuBroadcaster_BrowserConsole"
-                            accesskey="&browserConsoleCmd.accesskey;"/>
-                  <menuitem id="menu_responsiveUI"
-                            observes="devtoolsMenuBroadcaster_ResponsiveUI"
-                            accesskey="&responsiveDesignMode.accesskey;"/>
-                  <menuitem id="menu_eyedropper"
-                            observes="devtoolsMenuBroadcaster_Eyedropper"
-                            accesskey="&eyedropper.accesskey;"/>
-                  <menuitem id="menu_scratchpad"
-                            observes="devtoolsMenuBroadcaster_Scratchpad"
-                            accesskey="&scratchpad.accesskey;"/>
                   <menuitem id="menu_pageSource"
                             observes="devtoolsMenuBroadcaster_PageSource"
                             accesskey="&pageSourceCmd.accesskey;"/>
-                  <menuitem id="javascriptConsole"
-                            observes="devtoolsMenuBroadcaster_ErrorConsole"
-                            accesskey="&errorConsoleCmd.accesskey;"/>
-                  <menuitem id="menu_devtools_serviceworkers"
-                            observes="devtoolsMenuBroadcaster_ServiceWorkers"
-                            accesskey="&devtoolsServiceWorkers.accesskey;"/>
-                  <menuitem id="menu_devtools_connect"
-                            observes="devtoolsMenuBroadcaster_connect"/>
-                  <menuseparator id="devToolsEndSeparator"/>
-                  <menuitem id="getMoreDevtools"
-                            observes="devtoolsMenuBroadcaster_GetMoreTools"
-                            accesskey="&getMoreDevtoolsCmd.accesskey;"/>
                 </menupopup>
               </menu>
               <menuitem id="menu_pageInfo"
                         accesskey="&pageInfoCmd.accesskey;"
                         label="&pageInfoCmd.label;"
 #ifndef XP_WIN
                         key="key_viewInfo"
 #endif
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -90,30 +90,17 @@
     <command id="cmd_gestureRotateRight" oncommand="gGestureSupport.rotate(event.sourceEvent)"/>
     <command id="cmd_gestureRotateEnd" oncommand="gGestureSupport.rotateEnd()"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
     <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/>
     <command id="Browser:NewUserContextTab" oncommand="openNewUserContextTab(event.sourceEvent);" reserved="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:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
-    <command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
-    <command id="Tools:BrowserContentToolbox" oncommand="gDevToolsBrowser.openContentProcessToolbox();" disabled="true" hidden="true"/>
-    <command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/>
-    <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
-    <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
-    <command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
-    <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
-    <command id="Tools:ServiceWorkers" oncommand="gDevToolsBrowser.openAboutDebugging(gBrowser, 'workers')"/>
-    <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);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});" reserved="true"/>
 #ifdef E10S_TESTING_ONLY
     <command id="Tools:NonRemoteWindow"
       oncommand="OpenBrowserWindow({remote: false});"/>
 #endif
@@ -191,73 +178,22 @@
     <broadcaster id="sync-reauth-state" hidden="true"/>
     <broadcaster id="viewTabsSidebar" autoCheck="false" sidebartitle="&syncedTabs.sidebar.label;"
                  type="checkbox" group="sidebar"
                  sidebarurl="chrome://browser/content/syncedtabs/sidebar.xhtml"
                  oncommand="SidebarUI.toggle('viewTabsSidebar');"/>
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
 
-    <!-- DevTools broadcasters -->
-    <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
-                 label="&devToolboxMenuItem.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:DevToolbox"
-                 key="key_devToolboxMenuItem"/>
-    <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
-                 label="&devToolbarMenu.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:DevToolbar"
-                 key="key_devToolbar"/>
-    <broadcaster id="devtoolsMenuBroadcaster_webide"
-                 label="&webide.label;"
-                 command="Tools:WebIDE"
-                 key="key_webide"/>
-    <broadcaster id="devtoolsMenuBroadcaster_BrowserToolbox"
-                 label="&browserToolboxMenu.label;"
-                 key="key_browserToolbox"
-                 command="Tools:BrowserToolbox"/>
-    <broadcaster id="devtoolsMenuBroadcaster_BrowserContentToolbox"
-                 label="&browserContentToolboxMenu.label;"
-                 command="Tools:BrowserContentToolbox"/>
-    <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"/>
-    <broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
-                 label="&responsiveDesignMode.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:ResponsiveUI"
-                 key="key_responsiveUI"/>
-    <broadcaster id="devtoolsMenuBroadcaster_Eyedropper"
-                 label="&eyedropper.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:Eyedropper"/>
     <broadcaster id="devtoolsMenuBroadcaster_PageSource"
                  label="&pageSourceCmd.label;"
                  key="key_viewSource"
                  command="View:PageSource">
       <observes element="canViewSource" attribute="disabled"/>
     </broadcaster>
-    <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
-                 label="&errorConsoleCmd.label;"
-                 command="Tools:ErrorConsole"/>
-    <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
-                 label="&getMoreDevtoolsCmd.label;"
-                 oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
-    <broadcaster id="devtoolsMenuBroadcaster_ServiceWorkers"
-                 label="&devtoolsServiceWorkers.label;"
-                 command="Tools:ServiceWorkers"/>
-    <broadcaster id="devtoolsMenuBroadcaster_connect"
-                 label="&devtoolsConnect.label;"
-                 command="Tools:DevToolsConnect"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
          key="&newNavigatorCmd.key;"
          command="cmd_newNavigator"
          modifiers="accel"/>
     <key id="key_newNavigatorTab" key="&tabCmd.commandkey;" modifiers="accel" command="cmd_newNavigatorTab"/>
@@ -294,41 +230,16 @@
 #endif
 #ifdef XP_GNOME
     <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/>
     <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/>
 #else
     <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
 #endif
     <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
-    <key id="key_devToolboxMenuItemF12" keycode="&devToolsCmd.keycode;" keytext="&devToolsCmd.keytext;" command="Tools:DevToolbox"/>
-    <key id="key_browserConsole" key="&browserConsoleCmd.commandkey;" command="Tools:BrowserConsole" modifiers="accel,shift"/>
-    <key id="key_browserToolbox" key="&browserToolboxCmd.commandkey;" command="Tools:BrowserToolbox" modifiers="accel,alt,shift"/>
-    <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
-         keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
-    <key id="key_responsiveUI" key="&responsiveDesignMode.commandkey;" command="Tools:ResponsiveUI"
-#ifdef XP_MACOSX
-        modifiers="accel,alt"
-#else
-        modifiers="accel,shift"
-#endif
-    />
-    <key id="key_webide" keycode="&webide.keycode;" command="Tools:WebIDE"
-         modifiers="shift" keytext="&webide.keytext;"/>
-    <key id="key_devToolboxMenuItem" keytext="&devToolboxMenuItem.keytext;"
-         command="Tools:DevToolbox" key="&devToolboxMenuItem.keytext;"
-#ifdef XP_MACOSX
-        modifiers="accel,alt"
-#else
-        modifiers="accel,shift"
-#endif
-    />
-
-    <key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift"
-         keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/>
     <key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile"  modifiers="accel"/>
     <key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/>
     <key id="printKb" key="&printCmd.commandkey;" command="cmd_print"  modifiers="accel"/>
     <key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
     <key id="key_closeWindow" key="&closeCmd.key;" command="cmd_closeWindow" modifiers="accel,shift"/>
     <key id="key_toggleMute" key="&toggleMuteCmd.key;" command="cmd_toggleMute" modifiers="control"/>
     <key id="key_undo"
          key="&undoCmd.key;"
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -249,90 +249,25 @@ These should match what Safari and other
 <!ENTITY downloadsUnix.commandkey     "y">
 <!ENTITY addons.label                 "Add-ons">
 <!ENTITY addons.accesskey             "A">
 <!ENTITY addons.commandkey            "A">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
-<!ENTITY devToolsCmd.keycode          "VK_F12">
-<!ENTITY devToolsCmd.keytext          "F12">
-
-<!ENTITY devtoolsServiceWorkers.label      "Service Workers">
-<!ENTITY devtoolsServiceWorkers.accesskey  "k">
-
-<!ENTITY devtoolsConnect.label        "Connect…">
-<!ENTITY devtoolsConnect.accesskey    "e">
-
-<!ENTITY errorConsoleCmd.label        "Error Console">
-<!ENTITY errorConsoleCmd.accesskey    "C">
-
-<!ENTITY remoteWebConsoleCmd.label    "Remote Web Console">
-
-<!ENTITY browserConsoleCmd.label      "Browser Console">
-<!ENTITY browserConsoleCmd.commandkey "j">
-<!ENTITY browserConsoleCmd.accesskey  "B">
-
 <!ENTITY inspectContextMenu.label     "Inspect Element">
 <!ENTITY inspectContextMenu.accesskey "Q">
 
-<!ENTITY responsiveDesignMode.label   "Responsive Design Mode">
-<!ENTITY responsiveDesignMode.accesskey "R">
-<!ENTITY responsiveDesignMode.commandkey "M">
-
-<!ENTITY eyedropper.label   "Eyedropper">
-<!ENTITY eyedropper.accesskey "Y">
-
-<!-- LOCALIZATION NOTE (scratchpad.label): This menu item label appears
-  -  in the Tools menu. See bug 653093.
-  -  The Scratchpad is intended to provide a simple text editor for creating
-  -  and evaluating bits of JavaScript code for the purposes of function
-  -  prototyping, experimentation and convenient scripting.
-  -
-  -  It's quite possible that you won't have a good analogue for the word
-  -  "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 (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 browserToolboxCmd.commandkey "i">
-
-<!-- LOCALIZATION NOTE (browserContentToolboxMenu.label): This is the label for the
-  -  application menu item that opens the browser content toolbox UI in the Tools menu.
-  -  This toolbox allows to debug the chrome of the content process in multiprocess builds.  -->
-<!ENTITY browserContentToolboxMenu.label     "Browser Content Toolbox">
-<!ENTITY browserContentToolboxMenu.accesskey "x">
-
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
-<!ENTITY devToolbarMenu.label              "Developer Toolbar">
-<!ENTITY devToolbarMenu.accesskey          "v">
-<!ENTITY webide.label                      "WebIDE">
-<!ENTITY webide.accesskey                  "W">
-<!ENTITY webide.keycode                    "VK_F8">
-<!ENTITY webide.keytext                    "F8">
-<!ENTITY devToolbar.keycode                "VK_F2">
-<!ENTITY devToolbar.keytext                "F2">
-<!ENTITY devToolboxMenuItem.label          "Toggle Tools">
-<!ENTITY devToolboxMenuItem.accesskey      "T">
-<!ENTITY devToolboxMenuItem.keytext        "I">
 
 <!ENTITY devToolbarToolsButton.tooltip     "Toggle developer tools">
+
 <!ENTITY devToolbarOtherToolsButton.label  "More Tools">
 
-<!ENTITY getMoreDevtoolsCmd.label        "Get More Tools">
-<!ENTITY getMoreDevtoolsCmd.accesskey    "M">
-
 <!ENTITY fileMenu.label         "File"> 
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newUserContext.label             "New Container Tab">
 <!ENTITY newUserContext.accesskey         "C">
 <!ENTITY userContextPersonal.label        "Personal">
 <!ENTITY userContextPersonal.accesskey    "P">
 <!ENTITY userContextWork.label            "Work">
 <!ENTITY userContextWork.accesskey        "W">
--- a/devtools/client/framework/browser-menus.js
+++ b/devtools/client/framework/browser-menus.js
@@ -8,19 +8,158 @@
  * This module inject dynamically menu items and key shortcuts into browser UI.
  *
  * Menu and shortcut definitions are fetched from:
  * - devtools/client/menus for top level entires
  * - devtools/client/definitions for tool-specifics entries
  */
 
 const Services = require("Services");
+const MenuStrings = Services.strings.createBundle("chrome://devtools/locale/menus.properties");
 
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 
+// Keep list of inserted DOM Elements in order to remove them on unload
+// Maps browser xul document => list of DOM Elements
+const FragmentsCache = new Map();
+
+function l10n(key) {
+  return MenuStrings.GetStringFromName(key);
+}
+
+/**
+ * Create a xul:key element
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys are to be added.
+ * @param {String} l10nKey
+ *        Prefix of the properties entry to look for key shortcut in
+ *        localization file. We will look for {property}.key and
+ *        {property}.keytext for non-character shortcuts like F12.
+ * @param {String} command
+ *        Id of the xul:command to map to.
+ * @param {Object} key definition dictionnary
+ *        Definition with following attributes:
+ *        - {String} id
+ *          xul:key's id, automatically prefixed with "key_",
+ *        - {String} modifiers
+ *          Space separater list of modifier names,
+ *        - {Boolean} keytext
+ *          If true, consider the shortcut as a characther one,
+ *          otherwise a non-character one like F12.
+ *
+ * @return XULKeyElement
+ */
+function createKey(doc, l10nKey, command, key) {
+  let k = doc.createElement("key");
+  k.id = "key_" + key.id;
+  let shortcut = l10n(l10nKey + ".key");
+  if (shortcut.startsWith("VK_")) {
+    k.setAttribute("keycode", shortcut);
+    k.setAttribute("keytext", l10n(l10nKey + ".keytext"));
+  } else {
+    k.setAttribute("key", shortcut);
+  }
+  if (command) {
+    k.setAttribute("command", command);
+  }
+  if (key.modifiers) {
+    k.setAttribute("modifiers", key.modifiers);
+  }
+  return k;
+}
+
+/**
+ * Create a xul:menuitem element
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys are to be added.
+ * @param {String} id
+ *        Element id.
+ * @param {String} label
+ *        Menu label.
+ * @param {String} broadcasterId (optional)
+ *        Id of the xul:broadcaster to map to.
+ * @param {String} accesskey (optional)
+ *        Access key of the menuitem, used as shortcut while opening the menu.
+ * @param {Boolean} isCheckbox
+ *        If true, the menuitem will act as a checkbox and have an optional
+ *        tick on its left.
+ *
+ * @return XULMenuItemElement
+ */
+function createMenuItem({ doc, id, label, broadcasterId, accesskey, isCheckbox }) {
+  let menuitem = doc.createElement("menuitem");
+  menuitem.id = id;
+  if (label) {
+    menuitem.setAttribute("label", label);
+  }
+  if (broadcasterId) {
+    menuitem.setAttribute("observes", broadcasterId);
+  }
+  if (accesskey) {
+    menuitem.setAttribute("accesskey", accesskey);
+  }
+  if (isCheckbox) {
+    menuitem.setAttribute("type", "checkbox");
+    menuitem.setAttribute("autocheck", "false");
+  }
+  return menuitem;
+}
+
+/**
+ * Create a xul:broadcaster element
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys are to be added.
+ * @param {String} id
+ *        Element id.
+ * @param {String} label
+ *        Broadcaster label.
+ * @param {Boolean} isCheckbox
+ *        If true, the broadcaster is a checkbox one.
+ *
+ * @return XULMenuItemElement
+ */
+function createBroadcaster({ doc, id, label, isCheckbox }) {
+  let broadcaster = doc.createElement("broadcaster");
+  broadcaster.id = id;
+  broadcaster.setAttribute("label", label);
+  if (isCheckbox) {
+    broadcaster.setAttribute("type", "checkbox");
+    broadcaster.setAttribute("autocheck", "false");
+  }
+  return broadcaster;
+}
+
+/**
+ * Create a xul:command element
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys are to be added.
+ * @param {String} id
+ *        Element id.
+ * @param {String} oncommand
+ *        JS String to run when the command is fired.
+ * @param {Boolean} disabled
+ *        If true, the command is disabled and hidden.
+ *
+ * @return XULCommandElement
+ */
+function createCommand({ doc, id, oncommand, disabled }) {
+  let command = doc.createElement("command");
+  command.id = id;
+  command.setAttribute("oncommand", oncommand);
+  if (disabled) {
+    command.setAttribute("disabled", "true");
+    command.setAttribute("hidden", "true");
+  }
+  return command;
+}
+
 /**
  * Add a <key> to <keyset id="devtoolsKeyset">.
  * Appending a <key> element is not always enough. The <keyset> needs
  * to be detached and reattached to make sure the <key> is taken into
  * account (see bug 832984).
  *
  * @param {XULDocument} doc
  *        The document to which keys are to be added
@@ -50,52 +189,54 @@ function attachKeybindingsToBrowser(doc,
 function createToolMenuElements(toolDefinition, doc) {
   let id = toolDefinition.id;
 
   // Prevent multiple entries for the same tool.
   if (doc.getElementById("Tools:" + id)) {
     return;
   }
 
-  let cmd = doc.createElement("command");
-  cmd.id = "Tools:" + id;
-  cmd.setAttribute("oncommand",
-      'gDevToolsBrowser.selectToolCommand(gBrowser, "' + id + '");');
+  let cmd = createCommand({
+    doc,
+    id: "Tools:" + id,
+    oncommand: 'gDevToolsBrowser.selectToolCommand(gBrowser, "' + id + '");',
+  });
 
   let key = null;
   if (toolDefinition.key) {
     key = doc.createElement("key");
     key.id = "key_" + id;
 
     if (toolDefinition.key.startsWith("VK_")) {
       key.setAttribute("keycode", toolDefinition.key);
     } else {
       key.setAttribute("key", toolDefinition.key);
     }
 
     key.setAttribute("command", cmd.id);
     key.setAttribute("modifiers", toolDefinition.modifiers);
   }
 
-  let bc = doc.createElement("broadcaster");
-  bc.id = "devtoolsMenuBroadcaster_" + id;
-  bc.setAttribute("label", toolDefinition.menuLabel || toolDefinition.label);
+  let bc = createBroadcaster({
+    doc,
+    id: "devtoolsMenuBroadcaster_" + id,
+    label: toolDefinition.menuLabel || toolDefinition.label
+  });
   bc.setAttribute("command", cmd.id);
 
   if (key) {
     bc.setAttribute("key", "key_" + id);
   }
 
-  let menuitem = doc.createElement("menuitem");
-  menuitem.id = "menuitem_" + id;
-  menuitem.setAttribute("observes", "devtoolsMenuBroadcaster_" + id);
-
-  if (toolDefinition.accesskey) {
-    menuitem.setAttribute("accesskey", toolDefinition.accesskey);
-  }
+  let menuitem = createMenuItem({
+    doc,
+    id: "menuitem_" + id,
+    broadcasterId: "devtoolsMenuBroadcaster_" + id,
+    accesskey: toolDefinition.accesskey
+  });
 
   return {
     cmd: cmd,
     key: key,
     bc: bc,
     menuitem: menuitem
   };
 }
@@ -208,29 +349,123 @@ function addAllToolsToMenu(doc) {
 
   let mps = doc.getElementById("menu_devtools_separator");
   if (mps) {
     mps.parentNode.insertBefore(fragMenuItems, mps);
   }
 }
 
 /**
- * Detect the presence of a Firebug.
+ * Add global menus and shortcuts that are not panel specific.
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys and menus are to be added.
  */
-function isFirebugInstalled() {
-  let bootstrappedAddons = Services.prefs.getCharPref("extensions.bootstrappedAddons");
-  return bootstrappedAddons.indexOf("firebug@software.joehewitt.com") != -1;
+function addTopLevelItems(doc) {
+  let keys = doc.createDocumentFragment();
+  let menuItems = doc.createDocumentFragment();
+
+  let { menuitems } = require("../menus");
+  for (let item of menuitems) {
+    if (item.separator) {
+      let separator = doc.createElement("menuseparator");
+      separator.id = item.id;
+      menuItems.appendChild(separator);
+    } else {
+      let { id, l10nKey } = item;
+
+      // Create a <menuitem>
+      let menuitem = createMenuItem({
+        doc,
+        id,
+        label: l10n(l10nKey + ".label"),
+        accesskey: l10n(l10nKey + ".accesskey"),
+        isCheckbox: item.checkbox
+      });
+      menuitem.addEventListener("command", item.oncommand);
+      menuItems.appendChild(menuitem);
+
+      if (item.key && l10nKey) {
+        // Create a <key>
+        let key = createKey(doc, l10nKey, null, item.key);
+        // Bug 371900: command event is fired only if "oncommand" attribute is set.
+        key.setAttribute("oncommand", ";");
+        key.addEventListener("command", item.oncommand);
+        // Refer to the key in order to display the key shortcut at menu ends
+        menuitem.setAttribute("key", key.id);
+        keys.appendChild(key);
+      }
+      if (item.additionalKeys) {
+        // Create additional <key>
+        for (let key of item.additionalKeys) {
+          let node = createKey(doc, key.l10nKey, null, key);
+          // Bug 371900: command event is fired only if "oncommand" attribute is set.
+          node.setAttribute("oncommand", ";");
+          node.addEventListener("command", item.oncommand);
+          keys.appendChild(node);
+        }
+      }
+    }
+  }
+
+  // Cache all nodes before insertion to be able to remove them on unload
+  let nodes = [];
+  for(let node of keys.children) {
+    nodes.push(node);
+  }
+  for(let node of menuItems.children) {
+    nodes.push(node);
+  }
+  FragmentsCache.set(doc, nodes);
+
+  attachKeybindingsToBrowser(doc, keys);
+
+  let menu = doc.getElementById("menuWebDeveloperPopup");
+  menu.appendChild(menuItems);
+
+  // There is still "Page Source" menuitem hardcoded into browser.xul. Instead
+  // of manually inserting everything around it, move it to the expected
+  // position.
+  let pageSource = doc.getElementById("menu_pageSource");
+  let endSeparator = doc.getElementById("devToolsEndSeparator");
+  menu.insertBefore(pageSource, endSeparator);
+}
+
+/**
+ * Remove global menus and shortcuts that are not panel specific.
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys and menus are to be added.
+ */
+function removeTopLevelItems(doc) {
+  let nodes = FragmentsCache.get(doc);
+  if (!nodes) {
+    return;
+  }
+  FragmentsCache.delete(doc);
+  for (let node of nodes) {
+    node.remove();
+  }
 }
 
 /**
  * Add menus and shortcuts to a browser document
  *
  * @param {XULDocument} doc
  *        The document to which keys and menus are to be added.
  */
 exports.addMenus = function (doc) {
+  addTopLevelItems(doc);
+
   addAllToolsToMenu(doc);
+};
 
-  if (isFirebugInstalled()) {
-    let broadcaster = doc.getElementById("devtoolsMenuBroadcaster_DevToolbox");
-    broadcaster.removeAttribute("key");
-  }
+/**
+ * Remove menus and shortcuts from a browser document
+ *
+ * @param {XULDocument} doc
+ *        The document to which keys and menus are to be removed.
+ */
+exports.removeMenus = function (doc) {
+  // We only remove top level entries. Per-tool entries are removed while
+  // unregistering each tool.
+  removeTopLevelItems(doc);
 };
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -75,64 +75,64 @@ var gDevToolsBrowser = exports.gDevTools
   /**
    * This function ensures the right commands are enabled in a window,
    * depending on their relevant prefs. It gets run when a window is registered,
    * or when any of the devtools prefs change.
    */
   updateCommandAvailability: function(win) {
     let doc = win.document;
 
-    function toggleCmd(id, isEnabled) {
+    function toggleMenuItem(id, isEnabled) {
       let cmd = doc.getElementById(id);
       if (isEnabled) {
         cmd.removeAttribute("disabled");
         cmd.removeAttribute("hidden");
       } else {
         cmd.setAttribute("disabled", "true");
         cmd.setAttribute("hidden", "true");
       }
     };
 
     // Enable developer toolbar?
     let devToolbarEnabled = Services.prefs.getBoolPref("devtools.toolbar.enabled");
-    toggleCmd("Tools:DevToolbar", devToolbarEnabled);
-    let focusEl = doc.getElementById("Tools:DevToolbarFocus");
+    toggleMenuItem("menu_devToolbar", devToolbarEnabled);
+    let focusEl = doc.getElementById("menu_devToolbar");
     if (devToolbarEnabled) {
       focusEl.removeAttribute("disabled");
     } else {
       focusEl.setAttribute("disabled", "true");
     }
     if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) {
       win.DeveloperToolbar.show(false).catch(console.error);
     }
 
     // Enable WebIDE?
     let webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled");
-    toggleCmd("Tools:WebIDE", webIDEEnabled);
+    toggleMenuItem("menu_webide", webIDEEnabled);
 
     let showWebIDEWidget = Services.prefs.getBoolPref("devtools.webide.widget.enabled");
     if (webIDEEnabled && showWebIDEWidget) {
       gDevToolsBrowser.installWebIDEWidget();
     } else {
       gDevToolsBrowser.uninstallWebIDEWidget();
     }
 
     // Enable Browser Toolbox?
     let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled");
     let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled");
     let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled;
-    toggleCmd("Tools:BrowserToolbox", remoteEnabled);
-    toggleCmd("Tools:BrowserContentToolbox", remoteEnabled && win.gMultiProcessBrowser);
+    toggleMenuItem("menu_browserToolbox", remoteEnabled);
+    toggleMenuItem("menu_browserContentToolbox", remoteEnabled && win.gMultiProcessBrowser);
 
     // Enable Error Console?
     let consoleEnabled = Services.prefs.getBoolPref("devtools.errorconsole.enabled");
-    toggleCmd("Tools:ErrorConsole", consoleEnabled);
+    toggleMenuItem("javascriptConsole", consoleEnabled);
 
     // Enable DevTools connection screen, if the preference allows this.
-    toggleCmd("Tools:DevToolsConnect", devtoolsRemoteEnabled);
+    toggleMenuItem("menu_devtools_connect", devtoolsRemoteEnabled);
   },
 
   observe: function(subject, topic, prefName) {
     switch (topic) {
       case "browser-delayed-startup-finished":
         this._registerBrowserWindow(subject);
         break;
       case "nsPref:changed":
@@ -149,17 +149,16 @@ var gDevToolsBrowser = exports.gDevTools
 
   ensurePrefObserver: function() {
     if (!this._prefObserverRegistered) {
       this._prefObserverRegistered = true;
       Services.prefs.addObserver("devtools.", this, false);
     }
   },
 
-
   /**
    * This function is for the benefit of Tools:{toolId} commands,
    * triggered from the WebDeveloper menu and keyboard shortcuts.
    *
    * selectToolCommand's behavior:
    * - if the toolbox is closed,
    *   we open the toolbox and select the tool
    * - if the toolbox is open, and the targeted tool is not selected,
@@ -343,24 +342,27 @@ var gDevToolsBrowser = exports.gDevTools
   moveWebIDEWidgetInNavbar: function() {
     CustomizableUI.addWidgetToArea("webide-button", CustomizableUI.AREA_NAVBAR);
   },
 
   /**
    * Add this DevTools's presence to a browser window's document
    *
    * @param {XULDocument} doc
-   *        The document to which menuitems and handlers are to be added
+   *        The document to which devtools should be hooked to.
    */
   _registerBrowserWindow: function(win) {
+    if (gDevToolsBrowser._trackedBrowserWindows.has(win)) {
+      return;
+    }
+    gDevToolsBrowser._trackedBrowserWindows.add(win);
+
     BrowserMenus.addMenus(win.document);
-
     this.updateCommandAvailability(win);
     this.ensurePrefObserver();
-    gDevToolsBrowser._trackedBrowserWindows.add(win);
     win.addEventListener("unload", this);
 
     let tabContainer = win.gBrowser.tabContainer;
     tabContainer.addEventListener("TabSelect", this, false);
     tabContainer.addEventListener("TabOpen", this, false);
     tabContainer.addEventListener("TabClose", this, false);
     tabContainer.addEventListener("TabPinned", this, false);
     tabContainer.addEventListener("TabUnpinned", this, false);
@@ -515,17 +517,17 @@ var gDevToolsBrowser = exports.gDevTools
    * Update the "Toggle Tools" checkbox in the developer tools menu. This is
    * called when a toolbox is created or destroyed.
    */
   _updateMenuCheckbox: function DT_updateMenuCheckbox() {
     for (let win of gDevToolsBrowser._trackedBrowserWindows) {
 
       let hasToolbox = gDevToolsBrowser.hasToolboxOpened(win);
 
-      let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
+      let broadcaster = win.document.getElementById("menu_devToolbox");
       if (hasToolbox) {
         broadcaster.setAttribute("checked", "true");
       } else {
         broadcaster.removeAttribute("checked");
       }
     }
   },
 
@@ -551,16 +553,18 @@ var gDevToolsBrowser = exports.gDevTools
    *
    * @param  {XULWindow} win
    *         The window containing the menu entry
    */
   _forgetBrowserWindow: function(win) {
     gDevToolsBrowser._trackedBrowserWindows.delete(win);
     win.removeEventListener("unload", this);
 
+    BrowserMenus.removeMenus(win.document);
+
     // Destroy toolboxes for closed window
     for (let [target, toolbox] of gDevTools._toolboxes) {
       if (toolbox.frame && toolbox.frame.ownerDocument.defaultView == win) {
         toolbox.destroy();
       }
     }
 
     let tabContainer = win.gBrowser.tabContainer;
new file mode 100644
--- /dev/null
+++ b/devtools/client/locales/en-US/menus.properties
@@ -0,0 +1,70 @@
+# 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/.
+
+devToolsCmd.key = VK_F12
+devToolsCmd.keytext = F12
+
+devtoolsServiceWorkers.label = Service Workers
+devtoolsServiceWorkers.accesskey = k
+
+devtoolsConnect.label = Connect…
+devtoolsConnect.accesskey = e
+
+errorConsoleCmd.label = Error Console
+errorConsoleCmd.accesskey = C
+
+browserConsoleCmd.label = Browser Console
+browserConsoleCmd.accesskey = B
+browserConsoleCmd.key = j
+
+responsiveDesignMode.label = Responsive Design Mode
+responsiveDesignMode.accesskey = R
+responsiveDesignMode.key = M
+
+eyedropper.label = Eyedropper
+eyedropper.accesskey = Y
+
+# LOCALIZATION NOTE (scratchpad.label): This menu item label appears
+# in the Tools menu. See bug 653093.
+# The Scratchpad is intended to provide a simple text editor for creating
+# and evaluating bits of JavaScript code for the purposes of function
+# prototyping, experimentation and convenient scripting.
+#
+# It's quite possible that you won't have a good analogue for the word
+# "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".
+scratchpad.label = Scratchpad
+scratchpad.accesskey = s
+scratchpad.key = VK_F4
+scratchpad.keytext = F4
+
+# LOCALIZATION NOTE (browserToolboxMenu.label): This is the label for the
+# application menu item that opens the browser toolbox UI in the Tools menu.
+browserToolboxMenu.label = Browser Toolbox
+browserToolboxMenu.accesskey = e
+browserToolboxMenu.key = i
+
+# LOCALIZATION NOTE (browserContentToolboxMenu.label): This is the label for the
+# application menu item that opens the browser content toolbox UI in the Tools menu.
+# This toolbox allows to debug the chrome of the content process in multiprocess builds.
+browserContentToolboxMenu.label = Browser Content Toolbox
+browserContentToolboxMenu.accesskey = x
+
+devToolbarMenu.label = Developer Toolbar
+devToolbarMenu.accesskey = v
+devToolbarMenu.key = VK_F2
+devToolbarMenu.keytext = F2
+
+webide.label = WebIDE
+webide.accesskey = W
+webide.key = VK_F8
+webide.keytext = F8
+
+devToolboxMenuItem.label = Toggle Tools
+devToolboxMenuItem.accesskey = T
+devToolboxMenuItem.key = I
+
+getMoreDevtoolsCmd.label = Get More Tools
+getMoreDevtoolsCmd.accesskey = M
new file mode 100644
--- /dev/null
+++ b/devtools/client/menus.js
@@ -0,0 +1,207 @@
+/* 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";
+
+/**
+ * This module defines the sorted list of menuitems inserted into the
+ * "Web Developer" menu.
+ * It also defines the key shortcuts that relates to them.
+ *
+ * Various fields are necessary for historical compatiblity with XUL/addons:
+ * - id:
+ *   used as <xul:menuitem> id attribute
+ * - l10nKey:
+ *   prefix used to locale localization strings from menus.properties
+ * - oncommand:
+ *   function called when the menu item or key shortcut are fired
+ * - key:
+ *    - id:
+ *      prefixed by 'key_' to compute <xul:key> id attribute
+ *    - modifiers:
+ *      optional modifiers for the key shortcut
+ *    - keytext:
+ *      boolean, to set to true for key shortcut using regular character
+ * - additionalKeys:
+ *   Array of additional keys, see `key` definition.
+ * - disabled:
+ *   If true, the menuitem and key shortcut are going to be hidden and disabled
+ *   on startup, until some runtime code eventually enable them.
+ * - checkbox:
+ *   If true, the menuitem is prefixed by a checkbox and runtime code can
+ *   toggle it.
+ */
+
+const Services = require("Services");
+const isMac = Services.appinfo.OS === "Darwin";
+
+loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
+loader.lazyRequireGetter(this, "Eyedropper", "devtools/client/eyedropper/eyedropper", true);
+
+loader.lazyImporter(this, "BrowserToolboxProcess", "resource://devtools/client/framework/ToolboxProcess.jsm");
+loader.lazyImporter(this, "ResponsiveUIManager", "resource://devtools/client/responsivedesign/responsivedesign.jsm");
+loader.lazyImporter(this, "ScratchpadManager", "resource://devtools/client/scratchpad/scratchpad-manager.jsm");
+
+/**
+ * Detect the presence of a Firebug.
+ */
+function isFirebugInstalled() {
+  let bootstrappedAddons = Services.prefs
+    .getCharPref("extensions.bootstrappedAddons");
+  return bootstrappedAddons.indexOf("firebug@software.joehewitt.com") != -1;
+}
+
+exports.menuitems = [
+  { id: "menu_devToolbox",
+    l10nKey: "devToolboxMenuItem",
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      gDevToolsBrowser.toggleToolboxCommand(window.gBrowser);
+    },
+    key: {
+      id: "devToolboxMenuItem",
+      modifiers: isMac ? "accel,alt" : "accel,shift",
+      // This is the only one with a letter key
+      // and needs to be translated differently
+      keytext: true,
+    },
+    // This key conflicts with firebug, only enable it when it's not installed.
+    additionalKeys: !isFirebugInstalled() ? [{
+      id: "devToolboxMenuItemF12",
+      l10nKey: "devToolsCmd",
+    }] : null,
+    checkbox: true
+  },
+  { id: "menu_devtools_separator",
+    separator: true },
+  { id: "menu_devToolbar",
+    l10nKey: "devToolbarMenu",
+    disabled: true,
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      // Distinguish events when selecting a menuitem, where we either open
+      // or close the toolbar and when hitting the key shortcut where we just
+      // focus the toolbar if it doesn't already has it.
+      if (event.target.tagName.toLowerCase() == "menuitem") {
+        window.DeveloperToolbar.toggle();
+      } else {
+        window.DeveloperToolbar.focusToggle();
+      }
+    },
+    key: {
+      id: "devToolbar",
+      modifiers: "shift"
+    },
+    checkbox: true
+  },
+  { id: "menu_webide",
+    l10nKey: "webide",
+    disabled: true,
+    oncommand() {
+      gDevToolsBrowser.openWebIDE();
+    },
+    key: {
+      id: "webide",
+      modifiers: "shift"
+    }
+  },
+  { id: "menu_browserToolbox",
+    l10nKey: "browserToolboxMenu",
+    disabled: true,
+    oncommand() {
+      BrowserToolboxProcess.init();
+    },
+    key: {
+      id: "browserToolbox",
+      modifiers: "accel,alt,shift",
+      keytext: true
+    }
+  },
+  { id: "menu_browserContentToolbox",
+    l10nKey: "browserContentToolboxMenu",
+    disabled: true,
+    oncommand() {
+      gDevToolsBrowser.openContentProcessToolbox();
+    }
+  },
+  { id: "menu_browserConsole",
+    l10nKey: "browserConsoleCmd",
+    oncommand() {
+      let HUDService = require("devtools/client/webconsole/hudservice");
+      HUDService.openBrowserConsoleOrFocus();
+    },
+    key: {
+      id: "browserConsole",
+      modifiers: "accel,shift",
+      keytext: true
+    }
+  },
+  { id: "menu_responsiveUI",
+    l10nKey: "responsiveDesignMode",
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      ResponsiveUIManager.toggle(window, window.gBrowser.selectedTab);
+    },
+    key: {
+      id: "responsiveUI",
+      modifiers: isMac ? "accel,alt" : "accel,shift",
+      keytext: true
+    },
+    checkbox: true
+  },
+  { id: "menu_eyedropper",
+    l10nKey: "eyedropper",
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      let eyedropper = new Eyedropper(window, { context: "menu",
+                                                copyOnSelect: true });
+      eyedropper.open();
+    },
+    checkbox: true
+  },
+  { id: "menu_scratchpad",
+    l10nKey: "scratchpad",
+    oncommand() {
+      ScratchpadManager.openScratchpad();
+    },
+    key: {
+      id: "scratchpad",
+      modifiers: "shift"
+    }
+  },
+  { id: "javascriptConsole",
+    l10nKey: "errorConsoleCmd",
+    disabled: true,
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      window.toJavaScriptConsole();
+    }
+  },
+  { id: "menu_devtools_serviceworkers",
+    l10nKey: "devtoolsServiceWorkers",
+    disabled: true,
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      gDevToolsBrowser.openAboutDebugging(window.gBrowser, "workers");
+    }
+  },
+  { id: "menu_devtools_connect",
+    l10nKey: "devtoolsConnect",
+    disabled: true,
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      gDevToolsBrowser.openConnectScreen(window.gBrowser);
+    }
+  },
+  { separator: true,
+    id: "devToolsEndSeparator"
+  },
+  { id: "getMoreDevtools",
+    l10nKey: "getMoreDevtoolsCmd",
+    oncommand(event) {
+      let window = event.target.ownerDocument.defaultView;
+      window.openUILinkIn("https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/", "tab");
+    }
+  },
+];
--- a/devtools/client/moz.build
+++ b/devtools/client/moz.build
@@ -47,9 +47,10 @@ EXTRA_COMPONENTS += [
     'devtools-startup.manifest',
 ]
 
 JAR_MANIFESTS += ['jar.mn']
 
 DevToolsModules(
     'definitions.js',
     'main.js',
+    'menus.js',
 )
--- a/devtools/client/responsivedesign/responsivedesign.jsm
+++ b/devtools/client/responsivedesign/responsivedesign.jsm
@@ -437,24 +437,24 @@ ResponsiveUI.prototype = {
         break;
     }
   },
 
   /**
    * Check the menu items.
    */
    checkMenus: function RUI_checkMenus() {
-     this.chromeDoc.getElementById("Tools:ResponsiveUI").setAttribute("checked", "true");
+     this.chromeDoc.getElementById("menu_responsiveUI").setAttribute("checked", "true");
    },
 
   /**
    * Uncheck the menu items.
    */
    unCheckMenus: function RUI_unCheckMenus() {
-     this.chromeDoc.getElementById("Tools:ResponsiveUI").setAttribute("checked", "false");
+     this.chromeDoc.getElementById("menu_responsiveUI").setAttribute("checked", "false");
    },
 
   /**
    * Build the toolbar and the resizers.
    *
    * <vbox class="browserContainer"> From tabbrowser.xml
    *  <toolbar class="devtools-responsiveui-toolbar">
    *    <menulist class="devtools-responsiveui-menulist"/> // presets
--- a/devtools/client/responsivedesign/test/browser_responsiveruleview.js
+++ b/devtools/client/responsivedesign/test/browser_responsiveruleview.js
@@ -76,20 +76,20 @@ function* testEscapeOpensSplitConsole(in
   let onSplit = inspector._toolbox.once("split-console");
   EventUtils.synthesizeKey("VK_ESCAPE", {});
   yield onSplit;
 
   ok(inspector._toolbox._splitConsole, "Console is split after pressing ESC.");
 }
 
 function* testMenuItem(rdm) {
-  is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
+  is(document.getElementById("menu_responsiveUI").getAttribute("checked"),
      "true", "The menu item is checked");
 
   yield closeRDM(rdm);
 
-  is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
+  is(document.getElementById("menu_responsiveUI").getAttribute("checked"),
      "false", "The menu item is unchecked");
 }
 
 function numberOfRules(ruleView) {
   return ruleView.element.querySelectorAll(".ruleview-code").length;
 }
--- a/devtools/client/responsivedesign/test/browser_responsiveui.js
+++ b/devtools/client/responsivedesign/test/browser_responsiveui.js
@@ -5,17 +5,17 @@
 
 add_task(function*() {
   let tab = yield addTab("data:text/html,mop");
 
   let {rdm, manager} = yield openRDM(tab, "menu");
   let container = gBrowser.getBrowserContainer();
   is(container.getAttribute("responsivemode"), "true",
      "Should be in responsive mode.");
-  is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
+  is(document.getElementById("menu_responsiveUI").getAttribute("checked"),
      "true", "Menu item should be checked");
 
   ok(rdm, "An instance of the RDM should be attached to the tab.");
 
   let originalWidth = (yield getSizing()).width;
 
   let documentLoaded = waitForDocLoadComplete();
   gBrowser.loadURI("data:text/html;charset=utf-8,mop" +
@@ -55,26 +55,26 @@ add_task(function*() {
   yield resized;
 
   let currentSize = yield getSizing();
   is(currentSize.width, widthBeforeClose, "width should be restored");
   is(currentSize.height, heightBeforeClose, "height should be restored");
 
   container = gBrowser.getBrowserContainer();
   is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
-  is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
+  is(document.getElementById("menu_responsiveUI").getAttribute("checked"),
      "true", "menu item should be checked");
 
   let isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
   if (!isWinXP) {
     yield testScreenshot(rdm);
   }
 
   yield closeRDM(rdm);
-  is(document.getElementById("Tools:ResponsiveUI").getAttribute("checked"),
+  is(document.getElementById("menu_responsiveUI").getAttribute("checked"),
      "false", "menu item should be unchecked");
 });
 
 function* testPresets(rdm, manager) {
   // Starting from length - 4 because last 3 items are not presets :
   // the separator, the add button and the remove button
   for (let c = rdm.menulist.firstChild.childNodes.length - 4; c >= 0; c--) {
     let item = rdm.menulist.firstChild.childNodes[c];
--- a/devtools/client/responsivedesign/test/head.js
+++ b/devtools/client/responsivedesign/test/head.js
@@ -34,17 +34,17 @@ const { ResponsiveUIManager } = Cu.impor
  */
 var openRDM = Task.async(function*(tab = gBrowser.selectedTab,
                                    method = "menu") {
   let manager = ResponsiveUIManager;
 
   let opened = once(manager, "on");
   let resized = once(manager, "contentResize");
   if (method == "menu") {
-    document.getElementById("Tools:ResponsiveUI").doCommand();
+    document.getElementById("menu_responsiveUI").doCommand();
   } else {
     synthesizeKeyFromKeyTag(document.getElementById("key_responsiveUI"));
   }
   yield opened;
 
   let rdm = manager.getResponsiveUIForTab(tab);
   rdm.transitionsEnabled = false;
   registerCleanupFunction(() => {
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -24,16 +24,17 @@ loader.lazyGetter(this, "prefBranch", fu
 });
 loader.lazyGetter(this, "toolboxStrings", function () {
   return Services.strings.createBundle("chrome://devtools/locale/toolbox.properties");
 });
 
 loader.lazyRequireGetter(this, "gcliInit", "devtools/shared/gcli/commands/index");
 loader.lazyRequireGetter(this, "util", "gcli/util/util");
 loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/shared/webconsole/utils", true);
+loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
 
 /**
  * A collection of utilities to help working with commands
  */
 var CommandUtils = {
   /**
    * Utility to ensure that things are loaded in the correct order
    */
@@ -313,18 +314,21 @@ DeveloperToolbar.prototype.createToolbar
 
   let hbox = this._doc.createElement("hbox");
   hbox.setAttribute("class", "gclitoolbar-complete-node");
   stack.appendChild(hbox);
 
   let toolboxBtn = this._doc.createElement("toolbarbutton");
   toolboxBtn.setAttribute("id", "developer-toolbar-toolbox-button");
   toolboxBtn.setAttribute("class", "developer-toolbar-button");
-  toolboxBtn.setAttribute("observes", "devtoolsMenuBroadcaster_DevToolbox");
   toolboxBtn.setAttribute("tooltiptext", "devToolbarToolsButton.tooltip");
+  toolboxBtn.addEventListener("command", function (event) {
+    let window = event.target.ownerDocument.defaultView;
+    gDevToolsBrowser.toggleToolboxCommand(window.gBrowser);
+  });
 
   // On Mac, the close button is on the left,
   // while it is on the right on every other platforms.
   if (isMac) {
     toolbar.appendChild(close);
     toolbar.appendChild(stack);
     toolbar.appendChild(toolboxBtn);
   } else {
@@ -427,17 +431,17 @@ DeveloperToolbar.prototype.show = functi
     // write to, so this needs to be done asynchronously.
     let panelPromises = [
       TooltipPanel.create(this),
       OutputPanel.create(this)
     ];
     return promise.all(panelPromises).then(panels => {
       [ this.tooltipPanel, this.outputPanel ] = panels;
 
-      this._doc.getElementById("Tools:DevToolbar").setAttribute("checked", "true");
+      this._doc.getElementById("menu_devToolbar").setAttribute("checked", "true");
 
       this.target = TargetFactory.forTab(this._chromeWindow.gBrowser.selectedTab);
       const options = {
         environment: CommandUtils.createEnvironment(this, "target"),
         document: this.outputPanel.document,
       };
       return CommandUtils.createRequisition(this.target, options).then(requisition => {
         this.requisition = requisition;
@@ -549,17 +553,17 @@ DeveloperToolbar.prototype.hide = functi
   // show() is async, so ensure we don't need to wait for show() to finish
   var waitPromise = this._showPromise || promise.resolve();
 
   this._hidePromise = waitPromise.then(() => {
     this._element.hidden = true;
 
     Services.prefs.setBoolPref("devtools.toolbar.visible", false);
 
-    this._doc.getElementById("Tools:DevToolbar").setAttribute("checked", "false");
+    this._doc.getElementById("menu_devToolbar").setAttribute("checked", "false");
     this.destroy();
 
     this._telemetry.toolClosed("developertoolbar");
     this._notify(NOTIFICATIONS.HIDE);
 
     this._hidePromise = null;
   });
 
--- a/devtools/client/shared/test/browser_toolbar_basic.js
+++ b/devtools/client/shared/test/browser_toolbar_basic.js
@@ -15,17 +15,17 @@ add_task(function*() {
   document.getElementById("menu_devToolbar").doCommand();
   yield shown;
   ok(DeveloperToolbar.visible, "DeveloperToolbar is visible in checkOpen");
 
   let close = document.getElementById("developer-toolbar-closebutton");
   ok(close, "Close button exists");
 
   let toggleToolbox =
-    document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
+    document.getElementById("menu_devToolbox");
   ok(!isChecked(toggleToolbox), "toggle toolbox button is not checked");
 
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   let toolbox = yield gDevTools.showToolbox(target, "inspector");
   ok(isChecked(toggleToolbox), "toggle toolbox button is checked");
 
   yield addTab("about:blank");
   info("Opened a new tab");