Bug 1248603 - Register devtools menuitems dynamically. r=gijs,jryans
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 01 Apr 2016 05:49:00 -0700
changeset 291390 9b9b8514c6b0479d470b0c30f84b6e9552591da5
parent 291389 0b016f319532937405bf971cdb1e426e81bc35f5
child 291391 97e1c3fdf6f22c4a643b378eec2b775d9d95bb3d
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgijs, jryans
bugs1248603
milestone48.0a1
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");