Merge m-c to fx-team
authorJoe Walker <jwalker@mozilla.com>
Fri, 30 Nov 2012 13:51:45 +0000
changeset 123677 d2fbc67f69f54f096db0f202fa862c6e53284d0f
parent 123675 1b7103181091dad4c34f37111dcd8fc6ed0e5aa7 (current diff)
parent 123676 c77b869c20253968e3a4b40fdd33265ba6bc4030 (diff)
child 123678 5c8ee6600533b0cdb48bb5d7b6713b987907dda5
child 123727 d188dbaa49b1ec2d7fc560635f5169726cf2b3eb
child 124006 1edb4b4b310a38251a3320483698ee8903529b0a
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.0a1
first release with
nightly linux32
d2fbc67f69f5 / 20.0a1 / 20121201030812 / files
nightly linux64
d2fbc67f69f5 / 20.0a1 / 20121201030812 / files
nightly mac
d2fbc67f69f5 / 20.0a1 / 20121201030812 / files
nightly win32
d2fbc67f69f5 / 20.0a1 / 20121201030812 / files
nightly win64
d2fbc67f69f5 / 20.0a1 / 20121201030812 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
browser/devtools/debugger/test/browser_dbg_panesize.js
browser/devtools/highlighter/CmdInspect.jsm
browser/devtools/highlighter/Makefile.in
browser/devtools/highlighter/highlighter.jsm
browser/devtools/highlighter/inspector.jsm
browser/devtools/highlighter/test/Makefile.in
browser/devtools/highlighter/test/browser_inspector_breadcrumbs.html
browser/devtools/highlighter/test/browser_inspector_breadcrumbs.js
browser/devtools/highlighter/test/browser_inspector_bug_566084_location_changed.js
browser/devtools/highlighter/test/browser_inspector_bug_665880.js
browser/devtools/highlighter/test/browser_inspector_bug_672902_keyboard_shortcuts.js
browser/devtools/highlighter/test/browser_inspector_bug_674871.js
browser/devtools/highlighter/test/browser_inspector_bug_690361.js
browser/devtools/highlighter/test/browser_inspector_bug_699308_iframe_navigation.js
browser/devtools/highlighter/test/browser_inspector_changes.js
browser/devtools/highlighter/test/browser_inspector_cmd_inspect.html
browser/devtools/highlighter/test/browser_inspector_cmd_inspect.js
browser/devtools/highlighter/test/browser_inspector_destroyselection.html
browser/devtools/highlighter/test/browser_inspector_destroyselection.js
browser/devtools/highlighter/test/browser_inspector_highlighter.js
browser/devtools/highlighter/test/browser_inspector_highlighter_autohide.js
browser/devtools/highlighter/test/browser_inspector_iframeTest.js
browser/devtools/highlighter/test/browser_inspector_infobar.js
browser/devtools/highlighter/test/browser_inspector_initialization.js
browser/devtools/highlighter/test/browser_inspector_invalidate.js
browser/devtools/highlighter/test/browser_inspector_keybindings.js
browser/devtools/highlighter/test/browser_inspector_menu.js
browser/devtools/highlighter/test/browser_inspector_pseudoClass_menu.js
browser/devtools/highlighter/test/browser_inspector_pseudoclass_lock.js
browser/devtools/highlighter/test/browser_inspector_ruleviewstore.js
browser/devtools/highlighter/test/browser_inspector_scrolling.js
browser/devtools/highlighter/test/browser_inspector_sidebarstate.js
browser/devtools/highlighter/test/browser_inspector_tab_switch.js
browser/devtools/highlighter/test/browser_inspector_treeSelection.js
browser/devtools/highlighter/test/browser_inspector_tree_height.js
browser/devtools/highlighter/test/head.js
browser/devtools/highlighter/test/helpers.js
browser/devtools/layoutview/LayoutView.jsm
browser/devtools/tilt/test/browser_tilt_04_initialization-key.js
browser/devtools/webconsole/test/browser_webconsole_bug_581231_close_button.js
browser/devtools/webconsole/test/browser_webconsole_bug_601909_remember_height.js
browser/devtools/webconsole/test/browser_webconsole_bug_663443_panel_title.js
browser/devtools/webconsole/test/browser_webconsole_menustatus.js
browser/devtools/webconsole/test/browser_webconsole_position_ui.js
browser/devtools/webconsole/test/browser_webconsole_window_zombie.js
browser/themes/gnomestripe/devtools/layout-background.png
browser/themes/gnomestripe/devtools/layout-buttons.png
browser/themes/gnomestripe/devtools/treepanel-button.png
browser/themes/pinstripe/devtools/layout-background.png
browser/themes/pinstripe/devtools/layout-buttons.png
browser/themes/pinstripe/devtools/treepanel-button.png
browser/themes/winstripe/devtools/layout-background.png
browser/themes/winstripe/devtools/layout-buttons.png
browser/themes/winstripe/devtools/treepanel-button.png
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -998,21 +998,26 @@ pref("services.sync.prefs.sync.xpinstall
 pref("devtools.errorconsole.enabled", false);
 
 // Developer toolbar and GCLI preferences
 pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.gcli.allowSet", false);
 pref("devtools.commands.dir", "");
 
+// Toolbox preferences
+pref("devtools.toolbox.footer.height", 250);
+pref("devtools.toolbox.sidebar.width", 500);
+pref("devtools.toolbox.host", "bottom");
+pref("devtools.toolbox.selectedTool", "webconsole");
+pref("devtools.toolbox.toolbarSpec", '["tilt toggle","scratchpad","resize toggle"]');
+pref("devtools.toolbox.sideEnabled", false);
+
 // Enable the Inspector
 pref("devtools.inspector.enabled", true);
-pref("devtools.inspector.htmlHeight", 112);
-pref("devtools.inspector.htmlPanelOpen", false);
-pref("devtools.inspector.sidebarOpen", false);
 pref("devtools.inspector.activeSidebar", "ruleview");
 pref("devtools.inspector.markupPreview", false);
 
 // Enable the Layout View
 pref("devtools.layoutview.enabled", true);
 pref("devtools.layoutview.open", false);
 
 // Enable the Responsive UI tool
@@ -1034,27 +1039,21 @@ pref("devtools.debugger.ui.win-width", 9
 pref("devtools.debugger.ui.win-height", 400);
 pref("devtools.debugger.ui.stackframes-width", 200);
 pref("devtools.debugger.ui.variables-width", 300);
 pref("devtools.debugger.ui.panes-visible-on-startup", false);
 pref("devtools.debugger.ui.variables-sorting-enabled", true);
 pref("devtools.debugger.ui.variables-non-enum-visible", true);
 pref("devtools.debugger.ui.variables-searchbox-visible", false);
 
-// Enable the style inspector
-pref("devtools.styleinspector.enabled", true);
-
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
 
-// Enable the rules view
-pref("devtools.ruleview.enabled", true);
-
 // Enable the Scratchpad tool.
 pref("devtools.scratchpad.enabled", true);
 
 // The maximum number of recently-opened files stored.
 // Setting this preference to 0 will not clear any recent files, but rather hide
 // the 'Open Recent'-menu.
 pref("devtools.scratchpad.recentFilesMax", 10);
 
@@ -1069,27 +1068,16 @@ pref("devtools.chrome.enabled", false);
 pref("devtools.gcli.hideIntro", false);
 
 // How eager are we to show help: never=1, sometimes=2, always=3
 pref("devtools.gcli.eagerHelper", 2);
 
 // Do we allow the 'pref set' command
 pref("devtools.gcli.allowSet", false);
 
-// The last Web Console height. This is initially 0 which means that the Web
-// Console will use the default height next time it shows.
-// Change to -1 if you do not want the Web Console to remember its last height.
-pref("devtools.hud.height", 0);
-
-// Remember the Web Console position. Possible values:
-//   above - above the web page,
-//   below - below the web page,
-//   window - in a separate window/popup panel.
-pref("devtools.webconsole.position", "below");
-
 // Remember the Web Console filters
 pref("devtools.webconsole.filter.network", true);
 pref("devtools.webconsole.filter.networkinfo", true);
 pref("devtools.webconsole.filter.csserror", true);
 pref("devtools.webconsole.filter.cssparser", true);
 pref("devtools.webconsole.filter.exception", true);
 pref("devtools.webconsole.filter.jswarn", true);
 pref("devtools.webconsole.filter.error", true);
--- a/browser/base/content/browser-appmenu.inc
+++ b/browser/base/content/browser-appmenu.inc
@@ -145,30 +145,37 @@
                       label="&printSetupCmd.label;"
                       command="cmd_pageSetup"/>
           </menupopup>
       </splitmenu>
       <menuseparator class="appmenu-menuseparator"/>
       <menu id="appmenu_webDeveloper"
             label="&appMenuWebDeveloper.label;">
         <menupopup id="appmenu_webDeveloper_popup">
-          <menuitem id="appmenu_devToolbar" observes="devtoolsMenuBroadcaster_DevToolbar"/>
-          <menuitem id="appmenu_webConsole" observes="devtoolsMenuBroadcaster_WebConsole"/>
-          <menuitem id="appmenu_remoteWebConsole" observes="devtoolsMenuBroadcaster_RemoteWebConsole"/>
-          <menuitem id="appmenu_pageinspect" observes="devtoolsMenuBroadcaster_Inspect"/>
-          <menuitem id="appmenu_responsiveUI" observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
-          <menuitem id="appmenu_debugger" observes="devtoolsMenuBroadcaster_Debugger"/>
-          <menuitem id="appmenu_remoteDebugger" observes="devtoolsMenuBroadcaster_RemoteDebugger"/>
-          <menuitem id="appmenu_chromeDebugger" observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
-          <menuitem id="appmenu_scratchpad" observes="devtoolsMenuBroadcaster_Scratchpad"/>
-          <menuitem id="appmenu_styleeditor" observes="devtoolsMenuBroadcaster_StyleEditor"/>
-          <menuitem id="appmenu_pageSource" observes="devtoolsMenuBroadcaster_PageSource"/>
-          <menuitem id="appmenu_errorConsole" observes="devtoolsMenuBroadcaster_ErrorConsole"/>
+          <menuitem id="appmenu_devToolbox"
+                    observes="devtoolsMenuBroadcaster_DevToolbox"/>
+          <menuseparator id="appmenu_devtools_separator"/>
+          <menuitem id="appmenu_devToolbar"
+                    observes="devtoolsMenuBroadcaster_DevToolbar"/>
+          <menuitem id="appmenu_chromeDebugger"
+                    observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
+          <menuitem id="appmenu_responsiveUI"
+                    observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
+          <menuitem id="appmenu_scratchpad"
+                    observes="devtoolsMenuBroadcaster_Scratchpad"/>
+          <menuitem id="appmenu_pageSource"
+                    observes="devtoolsMenuBroadcaster_PageSource"/>
+          <menuitem id="appmenu_errorConsole"
+                    observes="devtoolsMenuBroadcaster_ErrorConsole"/>
+          <menuseparator id="appmenu_devToolsConnectSeparator"/>
+          <menuitem id="appmenu_devtools_connect"
+                    observes="devtoolsMenuBroadcaster_connect"/>
           <menuseparator id="appmenu_devToolsEndSeparator"/>
-          <menuitem id="appmenu_getMoreDevtools" observes="devtoolsMenuBroadcaster_GetMoreTools"/>
+          <menuitem id="appmenu_getMoreDevtools"
+                    observes="devtoolsMenuBroadcaster_GetMoreTools"/>
           <menuseparator/>
 #define ID_PREFIX appmenu_developer_
 #define OMIT_ACCESSKEYS
 #include browser-charsetmenu.inc
 #undef ID_PREFIX
 #undef OMIT_ACCESSKEYS
           <menuitem label="&goOfflineCmd.label;"
                     type="checkbox"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -559,30 +559,44 @@
                         observes="sync-syncnow-state"
                         oncommand="gSyncUI.doSync(event);"/>
 #endif
               <menuseparator id="devToolsSeparator"/>
               <menu id="webDeveloperMenu"
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
                 <menupopup id="menuWebDeveloperPopup">
-                  <menuitem id="menu_devToolbar" observes="devtoolsMenuBroadcaster_DevToolbar" accesskey="&devToolbarMenu.accesskey;"/>
-                  <menuitem id="webConsole" observes="devtoolsMenuBroadcaster_WebConsole" accesskey="&webConsoleCmd.accesskey;"/>
-                  <menuitem id="menu_remoteWebConsole" observes="devtoolsMenuBroadcaster_RemoteWebConsole"/>
-                  <menuitem id="menu_pageinspect" observes="devtoolsMenuBroadcaster_Inspect" accesskey="&inspectMenu.accesskey;"/>
-                  <menuitem id="menu_responsiveUI" observes="devtoolsMenuBroadcaster_ResponsiveUI" accesskey="&responsiveDesignTool.accesskey;"/>
-                  <menuitem id="menu_debugger" observes="devtoolsMenuBroadcaster_Debugger" accesskey="&debuggerMenu.accesskey;"/>
-                  <menuitem id="menu_remoteDebugger" observes="devtoolsMenuBroadcaster_RemoteDebugger"/>
-                  <menuitem id="menu_chromeDebugger" observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
-                  <menuitem id="menu_scratchpad" observes="devtoolsMenuBroadcaster_Scratchpad" accesskey="&scratchpad.accesskey;"/>
-                  <menuitem id="menu_styleeditor" observes="devtoolsMenuBroadcaster_StyleEditor" accesskey="&styleeditor.accesskey;"/>
-                  <menuitem id="menu_pageSource" observes="devtoolsMenuBroadcaster_PageSource" accesskey="&pageSourceCmd.accesskey;"/>
-                  <menuitem id="javascriptConsole" observes="devtoolsMenuBroadcaster_ErrorConsole" accesskey="&errorConsoleCmd.accesskey;"/>
+                  <menuitem id="menu_devToolbox"
+                            observes="devtoolsMenuBroadcaster_DevToolbox"
+                            accesskey="&devToolbox.accesskey;"/>
+                  <menuseparator id="menu_devtools_separator"/>
+                  <menuitem id="menu_devToolbar"
+                            observes="devtoolsMenuBroadcaster_DevToolbar"
+                            accesskey="&devToolbarMenu.accesskey;"/>
+                  <menuitem id="menu_chromeDebugger"
+                            observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
+                  <menuitem id="menu_responsiveUI"
+                            observes="devtoolsMenuBroadcaster_ResponsiveUI"
+                            accesskey="&responsiveDesignTool.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;"/>
+                  <menuseparator id="menu_devToolsConnectSeparator"/>
+                  <menuitem id="menu_devtools_connect"
+                            observes="devtoolsMenuBroadcaster_connect"/>
                   <menuseparator id="devToolsEndSeparator"/>
-                  <menuitem id="getMoreDevtools" observes="devtoolsMenuBroadcaster_GetMoreTools" accesskey="&getMoreDevtoolsCmd.accesskey;"/>
+                  <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
@@ -83,29 +83,25 @@
     <command id="cmd_fullZoomReduce"  oncommand="FullZoom.reduce()"/>
     <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/>
     <command id="cmd_fullZoomReset"   oncommand="FullZoom.reset()"/>
     <command id="cmd_fullZoomToggle"  oncommand="ZoomManager.toggleZoom();"/>
     <command id="Browser:OpenLocation" oncommand="openLocation();"/>
 
     <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/>
     <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/>
+    <command id="Tools:DevToolbox" oncommand="gDevTools.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:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/>
-    <command id="Tools:RemoteWebConsole" oncommand="HUDConsoleUI.toggleRemoteHUD();" disabled="true" hidden="true"/>
-    <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();"/>
-    <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true" hidden="true"/>
-    <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:ChromeDebugger" oncommand="DebuggerUI.toggleChromeDebugger();" disabled="true" hidden="true"/>
     <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true" hidden="true"/>
-    <command id="Tools:StyleEditor" oncommand="StyleEditor.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();" disabled="true" hidden="true"/>
     <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
+    <command id="Tools:DevToolsConnect" oncommand="DevToolsXULCommands.openConnectScreen(gBrowser)"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
       oncommand="OpenBrowserWindow({private: true});"/>
 #else
       oncommand="gPrivateBrowsingUI.toggleMode();"/>
 #endif
@@ -123,37 +119,16 @@
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
   </commandset>
 
-  <commandset id="inspectorCommands">
-    <command id="Inspector:Inspect"
-             oncommand="InspectorUI.toggleInspection();"/>
-    <command id="Inspector:Sidebar"
-             oncommand="InspectorUI.toggleSidebar();"/>
-    <command id="Inspector:Tilt"
-             oncommand="Tilt.initialize();"/>
-    <command id="Inspector:HTMLPanel"
-             oncommand="InspectorUI.toggleHTMLPanel();"/>
-    <command id="Inspector:CopyInner"
-             oncommand="InspectorUI.copyInnerHTML();"/>
-    <command id="Inspector:CopyOuter"
-             oncommand="InspectorUI.copyOuterHTML();"/>
-    <command id="Inspector:DeleteNode"
-             oncommand="InspectorUI.deleteNode();"/>
-    <command id="Inspector:ToggleVeil"
-             oncommand="InspectorUI.toggleVeil();"/>
-    <command id="Inspector:ToggleInfobar"
-             oncommand="InspectorUI.toggleInfobar();"/>
-  </commandset>
-
   <broadcasterset id="mainBroadcasterSet">
     <broadcaster id="viewBookmarksSidebar" autoCheck="false" label="&bookmarksButton.label;"
                  type="checkbox" group="sidebar" sidebarurl="chrome://browser/content/bookmarks/bookmarksPanel.xul"
                  oncommand="toggleSidebar('viewBookmarksSidebar');"/>
 
     <!-- for both places and non-places, the sidebar lives at
          chrome://browser/content/history/history-panel.xul so there are no
          problems when switching between versions -->
@@ -192,71 +167,51 @@
     <broadcaster id="sync-setup-state"/>
     <broadcaster id="sync-syncnow-state"/>
 #endif
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
     <broadcaster id="socialActiveBroadcaster" hidden="true"/>
 
     <!-- DevTools broadcasters -->
+    <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
+                 label="&devToolbarToolsButton.label;"
+                 type="checkbox" autocheck="false"
+                 command="Tools:DevToolbox"/>
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
                  label="&devToolbarMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbar"
                  key="key_devToolbar"/>
-    <broadcaster id="devtoolsMenuBroadcaster_WebConsole"
-                 label="&webConsoleCmd.label;"
-                 type="checkbox" autocheck="false"
-                 key="key_webConsole"
-                 command="Tools:WebConsole"/>
-    <broadcaster id="devtoolsMenuBroadcaster_RemoteWebConsole"
-                 label="&remoteWebConsoleCmd.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:RemoteWebConsole"/>
-    <broadcaster id="devtoolsMenuBroadcaster_Inspect"
-                 label="&inspectMenu.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:Inspect"
-                 key="key_inspect"/>
-    <broadcaster id="devtoolsMenuBroadcaster_Debugger"
-                 label="&debuggerMenu.label2;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:Debugger"
-                 key="key_debugger"/>
-    <broadcaster id="devtoolsMenuBroadcaster_RemoteDebugger"
-                 label="&remoteDebuggerMenu.label;"
-                 command="Tools:RemoteDebugger"/>
     <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
                  label="&chromeDebuggerMenu.label;"
                  command="Tools:ChromeDebugger"/>
     <broadcaster id="devtoolsMenuBroadcaster_Scratchpad"
                  label="&scratchpad.label;"
                  command="Tools:Scratchpad"
                  key="key_scratchpad"/>
-    <broadcaster id="devtoolsMenuBroadcaster_StyleEditor"
-                 label="&styleeditor.label;"
-                 type="checkbox" autocheck="false"
-                 command="Tools:StyleEditor"
-                 key="key_styleeditor"/>
     <broadcaster id="devtoolsMenuBroadcaster_ResponsiveUI"
                  label="&responsiveDesignTool.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:ResponsiveUI"
                  key="key_responsiveUI"/>
     <broadcaster id="devtoolsMenuBroadcaster_PageSource"
                  label="&pageSourceCmd.label;"
                  key="key_viewSource"
                  command="View:PageSource"/>
     <broadcaster id="devtoolsMenuBroadcaster_ErrorConsole"
                  label="&errorConsoleCmd.label;"
                  key="key_errorConsole"
                  command="Tools:ErrorConsole"/>
     <broadcaster id="devtoolsMenuBroadcaster_GetMoreTools"
                  label="&getMoreDevtoolsCmd.label;"
                  oncommand="openUILinkIn('https://addons.mozilla.org/firefox/collections/mozilla/webdeveloper/', 'tab');"/>
+    <broadcaster id="devtoolsMenuBroadcaster_connect"
+                 label="&devtoolsConnect.label;"
+                 command="Tools:DevToolsConnect"/>
 
     <!-- SocialAPI broadcasters -->
     <broadcaster id="socialBroadcaster_userDetails"
                  notLoggedInLabel="&social.notLoggedIn.label;"/>
   </broadcasterset>
 
   <keyset id="mainKeyset">
     <key id="key_newNavigator"
@@ -268,17 +223,17 @@
          modifiers="accel"/>
 #ifndef XP_MACOSX
     <key id="focusURLBar2" key="&urlbar.accesskey;" command="Browser:OpenLocation"
          modifiers="alt"/>
 #endif
 
 #
 # Search Command Key Logic works like this:
-# 
+#
 # Unix: Ctrl+K (cross platform binding)
 #       Ctrl+J (in case of emacs Ctrl-K conflict)
 # Mac:  Cmd+K (cross platform binding)
 #       Cmd+Opt+F (platform convention)
 # Win:  Ctrl+K (cross platform binding)
 #       Ctrl+E (IE compat)
 #
 # We support Ctrl+K on all platforms now and advertise it in the menu since it is
@@ -300,48 +255,25 @@
     <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_errorConsole" key="&errorConsoleCmd.commandkey;" command="Tools:ErrorConsole" modifiers="accel,shift"/>
     <key id="key_devToolbar" keycode="&devToolbar.keycode;" modifiers="shift"
          keytext="&devToolbar.keytext;" command="Tools:DevToolbarFocus"/>
-    <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
-#ifdef XP_MACOSX
-        modifiers="accel,alt"
-#else
-        modifiers="accel,shift"
-#endif
-    />
-    <key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
-#ifdef XP_MACOSX
-        modifiers="accel,alt"
-#else
-        modifiers="accel,shift"
-#endif
-    />
-    <key id="key_inspect" key="&inspectMenu.commandkey;" command="Inspector:Inspect"
-#ifdef XP_MACOSX
-        modifiers="accel,alt"
-#else
-        modifiers="accel,shift"
-#endif
-    />
     <key id="key_responsiveUI" key="&responsiveDesignTool.commandkey;" command="Tools:ResponsiveUI"
 #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="key_styleeditor" keycode="&styleeditor.keycode;" modifiers="shift"
-         keytext="&styleeditor.keytext;" command="Tools:StyleEditor"/>
     <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_undo"
          key="&undoCmd.key;"
          modifiers="accel"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -557,20 +557,16 @@ statuspanel[inactive][previoustype=overL
 }
 
 .statuspanel-inner {
   height: 3em;
   width: 100%;
   -moz-box-align: end;
 }
 
-.styleInspector {
-  min-width: 350px;
-}
-
 .panel-inner-arrowcontentfooter[footertype="promobox"] {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#promobox");
 }
 
 /* tabview menus */
 .tabview-menuitem {
   max-width: 32em;
 }
@@ -588,32 +584,26 @@ html|*#gcli-output-frame,
 }
 
 .gclitoolbar-input-node,
 .gclitoolbar-complete-node,
 .gclitoolbar-prompt {
   direction: ltr;
 }
 
-#developer-toolbar-webconsole[error-count] > .toolbarbutton-icon {
+#developer-toolbar-toolbox-button[error-count] > .toolbarbutton-icon {
   display: none;
 }
 
-#developer-toolbar-webconsole[error-count]:before {
+#developer-toolbar-toolbox-button[error-count]:before {
   content: attr(error-count);
   display: -moz-box;
   -moz-box-pack: center;
 }
 
-/* We don't show the Style Editor button in the developer toolbar for now.
-   See bug 771203 */
-#developer-toolbar-styleeditor {
-  display: none;
-}
-
 /* Responsive Mode */
 
 .browserContainer[responsivemode] {
   overflow: auto;
 }
 
 .devtools-responsiveui-toolbar:-moz-locale-dir(rtl) {
   -moz-box-pack: end;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -110,38 +110,25 @@ XPCOMUtils.defineLazyGetter(this, "Popup
 });
 
 XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", tmp);
   return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar"));
 });
 
-XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
-  let tmp = {};
-  Cu.import("resource:///modules/inspector.jsm", tmp);
-  return new tmp.InspectorUI(window);
-});
-
 XPCOMUtils.defineLazyGetter(this, "DebuggerUI", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/DebuggerUI.jsm", tmp);
   return new tmp.DebuggerUI(window);
 });
 
-XPCOMUtils.defineLazyGetter(this, "Tilt", function() {
-  let tmp = {};
-  Cu.import("resource:///modules/devtools/Tilt.jsm", tmp);
-  return new tmp.Tilt(window);
-});
-
 XPCOMUtils.defineLazyModuleGetter(this, "Social",
   "resource:///modules/Social.jsm");
 
-
 XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
   "resource:///modules/PageThumbs.jsm");
 
 #ifdef MOZ_SAFE_BROWSING
 XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
   "resource://gre/modules/SafeBrowsing.jsm");
 #endif
 
@@ -1423,36 +1410,16 @@ var gBrowserInit = {
       document.getElementById("Tools:DevToolbarFocus").removeAttribute("disabled");
 
       // Show the toolbar if it was previously visible
       if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
         DeveloperToolbar.show(false);
       }
     }
 
-    // Enable Debugger?
-    let enabled = gPrefService.getBoolPref("devtools.debugger.enabled");
-    if (enabled) {
-      let cmd = document.getElementById("Tools:Debugger");
-      cmd.removeAttribute("disabled");
-      cmd.removeAttribute("hidden");
-    }
-
-    // Enable Remote Debugger?
-    let enabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
-    if (enabled) {
-      let cmd = document.getElementById("Tools:RemoteDebugger");
-      cmd.removeAttribute("disabled");
-      cmd.removeAttribute("hidden");
-
-      cmd = document.getElementById("Tools:RemoteWebConsole");
-      cmd.removeAttribute("disabled");
-      cmd.removeAttribute("hidden");
-    }
-
     // Enable Chrome Debugger?
     let enabled = gPrefService.getBoolPref("devtools.chrome.enabled") &&
                   gPrefService.getBoolPref("devtools.debugger.chrome-enabled") &&
                   gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (enabled) {
       let cmd = document.getElementById("Tools:ChromeDebugger");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
@@ -1471,24 +1438,16 @@ var gBrowserInit = {
     // Enable Scratchpad in the UI, if the preference allows this.
     let scratchpadEnabled = gPrefService.getBoolPref(Scratchpad.prefEnabledName);
     if (scratchpadEnabled) {
       let cmd = document.getElementById("Tools:Scratchpad");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
-    // Enable Style Editor?
-    let styleEditorEnabled = gPrefService.getBoolPref(StyleEditor.prefEnabledName);
-    if (styleEditorEnabled) {
-      let cmd = document.getElementById("Tools:StyleEditor");
-      cmd.removeAttribute("disabled");
-      cmd.removeAttribute("hidden");
-    }
-
 #ifdef MENUBAR_CAN_AUTOHIDE
     // If the user (or the locale) hasn't enabled the top-level "Character
     // Encoding" menu via the "browser.menu.showCharacterEncoding" preference,
     // hide it.
     if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding",
                                                Ci.nsIPrefLocalizedString).data)
       document.getElementById("appmenu_charsetMenu").hidden = true;
 #endif
@@ -1496,16 +1455,19 @@ var gBrowserInit = {
     // Enable Responsive UI?
     let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
     if (responsiveUIEnabled) {
       let cmd = document.getElementById("Tools:ResponsiveUI");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
+    // Add Devtools menuitems and listeners
+    gDevTools.registerBrowserWindow(window);
+
     let appMenuButton = document.getElementById("appmenu-button");
     let appMenuPopup = document.getElementById("appmenu-popup");
     if (appMenuButton && appMenuPopup) {
       let appMenuOpening = null;
       appMenuButton.addEventListener("mousedown", function(event) {
         if (event.button == 0)
           appMenuOpening = new Date();
       }, false);
@@ -1538,18 +1500,17 @@ var gBrowserInit = {
 
   onUnload: function() {
     // In certain scenarios it's possible for unload to be fired before onload,
     // (e.g. if the window is being closed after browser.js loads but before the
     // load completes). In that case, there's nothing to do here.
     if (!gStartupRan)
       return;
 
-    if (!__lookupGetter__("InspectorUI"))
-      InspectorUI.destroy();
+    gDevTools.forgetBrowserWindow(window);
 
     // First clean up services initialized in gBrowserInit.onLoad (or those whose
     // uninit methods don't depend on the services having been initialized).
     allTabs.uninit();
 
     CombinedStopReload.uninit();
 
     gGestureSupport.init(false);
@@ -1637,17 +1598,17 @@ var gBrowserInit = {
   // macBrowserOverlay
   nonBrowserWindowStartup: function() {
     // Disable inappropriate commands / submenus
     var disabledItems = ['Browser:SavePage',
                          'Browser:SendLink', 'cmd_pageSetup', 'cmd_print', 'cmd_find', 'cmd_findAgain',
                          'viewToolbarsMenu', 'viewSidebarMenuMenu', 'Browser:Reload',
                          'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', 'View:PageSource', 'View:FullScreen',
                          'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs',
-                         'View:PageInfo', 'Tasks:InspectPage', 'Browser:ToggleTabView', 'Browser:ToggleAddonBar'];
+                         'View:PageInfo', 'Browser:ToggleTabView', 'Browser:ToggleAddonBar'];
     var element;
 
     for (let disabledItem of disabledItems) {
       element = document.getElementById(disabledItem);
       if (element)
         element.setAttribute("disabled", "true");
     }
 
@@ -7443,16 +7404,22 @@ var TabContextMenu = {
       PlacesCommandHook.updateBookmarkAllTabsCommand();
 
     // Hide "Move to Group" if it's a pinned tab.
     document.getElementById("context_tabViewMenu").hidden =
       (this.contextTab.pinned || !TabView.firstUseExperienced);
   }
 };
 
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "DevToolsXULCommands",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+
 XPCOMUtils.defineLazyGetter(this, "HUDConsoleUI", function () {
   let tempScope = {};
   Cu.import("resource:///modules/HUDService.jsm", tempScope);
   try {
     return tempScope.HUDService.consoleUI;
   }
   catch (ex) {
     Components.utils.reportError(ex);
@@ -7539,51 +7506,16 @@ var ResponsiveUI = {
 };
 
 XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
   let tmp = {};
   Cu.import("resource:///modules/devtools/responsivedesign.jsm", tmp);
   return tmp.ResponsiveUIManager;
 });
 
-var StyleEditor = {
-  prefEnabledName: "devtools.styleeditor.enabled",
-  /**
-   * Opens the style editor. If the UI is already open, it will be focused.
-   *
-   * @param {CSSStyleSheet} [aSelectedStyleSheet] default Stylesheet.
-   * @param {Number} [aLine] Line to which the caret should be moved (one-indexed).
-   * @param {Number} [aCol] Column to which the caret should be moved (one-indexed).
-   */
-  openChrome: function SE_openChrome(aSelectedStyleSheet, aLine, aCol)
-  {
-    let contentWindow = gBrowser.selectedBrowser.contentWindow;
-    let win = this.StyleEditorManager.getEditorForWindow(contentWindow);
-    if (win) {
-      this.StyleEditorManager.selectEditor(win);
-      return win;
-    } else {
-      return this.StyleEditorManager.newEditor(contentWindow, window,
-                                               aSelectedStyleSheet, aLine, aCol);
-    }
-  },
-
-  toggle: function SE_toggle()
-  {
-    this.StyleEditorManager.toggleEditor(gBrowser.contentWindow, window);
-  }
-};
-
-XPCOMUtils.defineLazyGetter(StyleEditor, "StyleEditorManager", function() {
-  let tmp = {};
-  Cu.import("resource:///modules/devtools/StyleEditor.jsm", tmp);
-  return new tmp.StyleEditorManager(window);
-});
-
-
 XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
 #ifdef XP_WIN
   // Only show resizers on Windows 2000 and XP
   let sysInfo = Components.classes["@mozilla.org/system-info;1"]
                           .getService(Components.interfaces.nsIPropertyBag2);
   return parseFloat(sysInfo.getProperty("version")) < 6;
 #else
   return false;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -273,32 +273,16 @@
            onpopupshown="SocialFlyout.onShown()"
            onpopuphidden="SocialFlyout.onHidden()"
            side="right"
            type="arrow"
            hidden="true"
            noautofocus="true"
            position="topcenter topright"/>
 
-    <menupopup id="inspector-node-popup">
-      <menuitem id="inspectorHTMLCopyInner"
-                label="&inspectorHTMLCopyInner.label;"
-                accesskey="&inspectorHTMLCopyInner.accesskey;"
-                command="Inspector:CopyInner"/>
-      <menuitem id="inspectorHTMLCopyOuter"
-                label="&inspectorHTMLCopyOuter.label;"
-                accesskey="&inspectorHTMLCopyOuter.accesskey;"
-                command="Inspector:CopyOuter"/>
-      <menuseparator/>
-      <menuitem id="inspectorHTMLDelete"
-                label="&inspectorHTMLDelete.label;"
-                accesskey="&inspectorHTMLDelete.accesskey;"
-                command="Inspector:DeleteNode"/>
-    </menupopup>
-
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event);">
       <menuseparator/>
       <menuitem command="cmd_ToggleTabsOnTop"
                 type="checkbox"
                 label="&viewTabsOnTop.label;"
                 accesskey="&viewTabsOnTop.accesskey;"/>
       <menuitem command="cmd_CustomizeToolbars"
@@ -1060,29 +1044,16 @@
                   flex="1" contenttooltip="aHTMLTooltip"
                   tabcontainer="tabbrowser-tabs"
                   contentcontextmenu="contentAreaContextMenu"
                   autocompletepopup="PopupAutoComplete"
                   onclick="contentAreaClick(event, false);"/>
       <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
       <statuspanel id="statusbar-display" inactive="true"/>
     </vbox>
-    <splitter id="devtools-side-splitter" hidden="true"/>
-    <vbox id="devtools-sidebar-box" hidden="true"
-          style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
-      <toolbar id="devtools-sidebar-toolbar"
-               class="devtools-toolbar"
-               nowindowdrag="true">
-        <spacer flex="1"/>
-        <toolbarbutton tooltiptext="&inspectSidebarCloseButton.tooltiptext;"
-                       class="devtools-closebutton"
-                       command="Inspector:Sidebar"/>
-      </toolbar>
-      <deck id="devtools-sidebar-deck" flex="1"/>
-    </vbox>
     <splitter id="social-sidebar-splitter"
               class="chromeclass-extrachrome sidebar-splitter"
               observes="socialSidebarBroadcaster"/>
     <vbox id="social-sidebar-box"
           class="chromeclass-extrachrome"
           observes="socialSidebarBroadcaster"
           persist="width">
       <browser id="social-sidebar-browser"
@@ -1111,108 +1082,35 @@
           </hbox>
           <checkbox id="full-screen-remember-decision"/>
         </vbox>
       </vbox>
     </hbox>
   </hbox>
 
   <vbox id="browser-bottombox" layer="true">
-    <toolbar id="inspector-toolbar"
-             class="devtools-toolbar"
-             nowindowdrag="true"
-             hidden="true">
-#ifdef XP_MACOSX
-      <toolbarbutton id="highlighter-closebutton"
-                     class="devtools-closebutton"
-                     oncommand="InspectorUI.closeInspectorUI(false);"
-                     tooltiptext="&inspectCloseButton.tooltiptext;"/>
-#endif
-      <toolbarbutton id="inspector-inspect-toolbutton"
-                     class="devtools-toolbarbutton"
-                     command="Inspector:Inspect"/>
-      <toolbarbutton id="inspector-treepanel-toolbutton"
-                     class="devtools-toolbarbutton"
-                     tabindex="0"
-                     aria-label="&markupButton.arialabel;"
-                     accesskey="&markupButton.accesskey;"
-                     command="Inspector:HTMLPanel"/>
-      <arrowscrollbox id="inspector-breadcrumbs"
-                      flex="1" orient="horizontal"
-                      clicktoscroll="true"/>
-      <hbox id="inspector-tools">
-        <toolbarbutton id="inspector-3D-button"
-                       class="devtools-toolbarbutton"
-                       hidden="true"
-                       label="&inspect3DViewButton.label;"
-                       accesskey="&inspect3DViewButton.accesskey;"
-                       tabindex="0"
-                       command="Inspector:Tilt"/>
-        <toolbarbutton id="inspector-style-button"
-                       class="devtools-toolbarbutton"
-                       label="&inspectStyleButton.label;"
-                       accesskey="&inspectStyleButton.accesskey;"
-                       tabindex="0"
-                       command="Inspector:Sidebar"/>
-        <!-- registered tools go here -->
-      </hbox>
-#ifndef XP_MACOSX
-      <toolbarbutton id="highlighter-closebutton"
-                     class="devtools-closebutton"
-                     oncommand="InspectorUI.closeInspectorUI(false);"
-                     tooltiptext="&inspectCloseButton.tooltiptext;"/>
-#endif
-    </toolbar>
-
     <toolbar id="developer-toolbar"
              class="devtools-toolbar"
              hidden="true">
 #ifdef XP_MACOSX
           <toolbarbutton id="developer-toolbar-closebutton"
                          class="devtools-closebutton"
                          oncommand="DeveloperToolbar.hide();"
                          tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
 #endif
           <stack class="gclitoolbar-stack-node" flex="1">
             <hbox class="gclitoolbar-prompt">
               <label class="gclitoolbar-prompt-label">&#187;</label>
             </hbox>
             <hbox class="gclitoolbar-complete-node"/>
             <textbox class="gclitoolbar-input-node" rows="1"/>
           </stack>
-          <toolbarbutton id="developer-toolbar-webconsole"
-                         class="developer-toolbar-button"
-                         observes="devtoolsMenuBroadcaster_WebConsole"/>
-          <toolbarbutton id="developer-toolbar-inspector"
-                         class="developer-toolbar-button"
-                         observes="devtoolsMenuBroadcaster_Inspect"/>
-          <toolbarbutton id="developer-toolbar-styleeditor"
-                         class="developer-toolbar-button"
-                         observes="devtoolsMenuBroadcaster_StyleEditor"/>
-          <toolbarbutton id="developer-toolbar-debugger"
-                         class="developer-toolbar-button"
-                         observes="devtoolsMenuBroadcaster_Debugger"/>
-          <toolbarbutton id="developer-toolbar-other-tools"
-                         type="menu"
+          <toolbarbutton id="developer-toolbar-toolbox-button"
                          class="developer-toolbar-button"
-                         label="&devToolbarOtherToolsButton.label;">
-            <menupopup position="before_end">
-               <menuitem observes="devtoolsMenuBroadcaster_DevToolbar"/>
-               <menuitem observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
-               <menuitem observes="devtoolsMenuBroadcaster_RemoteDebugger"/>
-               <menuitem observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
-               <menuitem observes="devtoolsMenuBroadcaster_Scratchpad"/>
-               <menuitem observes="devtoolsMenuBroadcaster_StyleEditor"/>
-               <menuitem observes="devtoolsMenuBroadcaster_PageSource"/>
-               <menuitem observes="devtoolsMenuBroadcaster_ErrorConsole"/>
-               <menuseparator/>
-               <menuitem observes="devtoolsMenuBroadcaster_GetMoreTools"/>
-            </menupopup>
-          </toolbarbutton>
-
+                         observes="devtoolsMenuBroadcaster_DevToolbox"/>
 #ifndef XP_MACOSX
           <toolbarbutton id="developer-toolbar-closebutton"
                          class="devtools-closebutton"
                          oncommand="DeveloperToolbar.hide();"
                          tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
 #endif
    </toolbar>
 
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -1,131 +1,104 @@
 /* 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/. */
  
-#highlighter-container {
+.highlighter-container {
   pointer-events: none;
 }
 
-#highlighter-controls {
+.highlighter-controls {
   position: absolute;
   top: 0;
   left: 0;
 }
 
-#highlighter-outline-container {
+.highlighter-outline-container {
   overflow: hidden;
   position: relative;
 }
 
-#highlighter-outline {
+.highlighter-outline {
   position: absolute;
 }
 
-#highlighter-outline[hidden] {
+.highlighter-outline[hidden] {
   opacity: 0;
   pointer-events: none;
   display: -moz-box;
 }
 
-#highlighter-outline:not([disable-transitions]) {
+.highlighter-outline:not([disable-transitions]) {
   transition-property: opacity, top, left, width, height;
   transition-duration: 0.1s;
   transition-timing-function: linear;
 }
 
-.inspector-breadcrumbs-button {
-  direction: ltr;
-}
-
 /*
  * Node Infobar
  */
 
-#highlighter-nodeinfobar-container {
+.highlighter-nodeinfobar-container {
   position: absolute;
   max-width: 95%;
 }
 
-#highlighter-nodeinfobar-container[hidden] {
+.highlighter-nodeinfobar-container[hidden] {
   opacity: 0;
   pointer-events: none;
   display: -moz-box;
 }
 
-#highlighter-nodeinfobar-container:not([disable-transitions]),
-#highlighter-nodeinfobar-container[disable-transitions][force-transitions] {
+.highlighter-nodeinfobar-container:not([disable-transitions]),
+.highlighter-nodeinfobar-container[disable-transitions][force-transitions] {
   transition-property: transform, opacity, top, left;
   transition-duration: 0.1s;
   transition-timing-function: linear;
 }
 
-#highlighter-nodeinfobar-text {
+.highlighter-nodeinfobar-text {
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
   direction: ltr;
 }
 
 .highlighter-nodeinfobar-button > .toolbarbutton-text {
   display: none;
 }
 
-#highlighter-nodeinfobar-container:not([locked]):not(:hover) > #highlighter-nodeinfobar > .highlighter-nodeinfobar-button {
+.highlighter-nodeinfobar-container:not([locked]):not(:hover) > .highlighter-nodeinfobar > .highlighter-nodeinfobar-button {
   visibility: hidden;
 }
 
-#highlighter-nodeinfobar-container[locked] > #highlighter-nodeinfobar,
-#highlighter-nodeinfobar-container:not([locked]):hover > #highlighter-nodeinfobar {
+.highlighter-nodeinfobar-container[locked] > .highlighter-nodeinfobar,
+.highlighter-nodeinfobar-container:not([locked]):hover > .highlighter-nodeinfobar {
   pointer-events: auto;
 }
 
-html|*#highlighter-nodeinfobar-id,
-html|*#highlighter-nodeinfobar-classes,
-html|*#highlighter-nodeinfobar-pseudo-classes,
-html|*#highlighter-nodeinfobar-tagname {
+html|*.highlighter-nodeinfobar-id,
+html|*.highlighter-nodeinfobar-classes,
+html|*.highlighter-nodeinfobar-pseudo-classes,
+html|*.highlighter-nodeinfobar-tagname {
   -moz-user-select: text;
   cursor: text;
 }
 
 .highlighter-nodeinfobar-arrow {
   display: none;
 }
 
-#highlighter-nodeinfobar-container[position="top"]:not([hide-arrow]) > #highlighter-nodeinfobar-arrow-bottom {
+.highlighter-nodeinfobar-container[position="top"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-bottom {
   display: block;
 }
 
-#highlighter-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > #highlighter-nodeinfobar-arrow-top {
+.highlighter-nodeinfobar-container[position="bottom"]:not([hide-arrow]) > .highlighter-nodeinfobar-arrow-top {
   display: block;
 }
 
-#highlighter-nodeinfobar-container[disabled] {
+.highlighter-nodeinfobar-container[disabled] {
   visibility: hidden;
 }
 
-html|*#highlighter-nodeinfobar-tagname {
+html|*.highlighter-nodeinfobar-tagname {
   text-transform: lowercase;
 }
-
-.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
-  display: none;
-}
-
-#inspector-option-toolbarbutton > .toolbarbutton-menu-dropmarker {
-  display: none;
-}
-
-#inspector-layoutview-container > iframe {
-  /* header size */
-  height: 28px;
-}
-
-#inspector-layoutview-container:not([disable-transitions]) > iframe {
-  transition-property: height;
-  transition-duration: 0.2s;
-}
-
-#inspector-layoutview-container > iframe[open] {
-  /* header size + layout view size: 28px + 145px */
-  height: 173px;
-}
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -407,21 +407,29 @@ nsContextMenu.prototype = {
         this.setItemAttr("context-video-showstats", "disabled", hasError);
         this.setItemAttr("context-video-hidestats", "disabled", hasError);
       }
     }
     this.showItem("context-media-sep-commands",  onMedia);
   },
 
   inspectNode: function CM_inspectNode() {
-    if (InspectorUI.isTreePanelOpen) {
-      InspectorUI.inspectNode(this.target);
-      InspectorUI.stopInspecting();
+    let gBrowser = this.browser.ownerDocument.defaultView.gBrowser;
+    let imported = {};
+    Cu.import("resource:///modules/devtools/Target.jsm", imported);
+    var target = imported.TargetFactory.forTab(gBrowser.selectedTab);
+    let inspector = gDevTools.getPanelForTarget("inspector", target);
+    if (inspector && inspector.isReady) {
+      inspector.selection.setNode(this.target);
     } else {
-      InspectorUI.openInspectorUI(this.target);
+      let toolbox = gDevTools.openToolboxForTab(target, "inspector");
+      toolbox.once("inspector-ready", function(event, panel) {
+        let inspector = gDevTools.getPanelForTarget("inspector", target);
+        inspector.selection.setNode(this.target, "browser-context-menu");
+      }.bind(this));
     }
   },
 
   // Set various context menu attributes based on the state of the world.
   setTarget: function (aNode, aRangeParent, aRangeOffset) {
     const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     if (aNode.namespaceURI == xulNS ||
         aNode.nodeType == Node.DOCUMENT_NODE ||
--- a/browser/devtools/Makefile.in
+++ b/browser/devtools/Makefile.in
@@ -8,24 +8,25 @@ topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH   = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/config.mk
 
 DIRS = \
-  highlighter \
+  inspector \
   markupview \
   webconsole \
   commandline \
   sourceeditor \
   styleeditor \
   styleinspector \
   tilt \
   scratchpad \
   debugger \
   layoutview \
   shared \
   responsivedesign \
+  framework \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/devtools/commandline/CmdBreak.jsm
+++ b/browser/devtools/commandline/CmdBreak.jsm
@@ -7,16 +7,22 @@ const { classes: Cc, interfaces: Ci, uti
 this.EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
                                   "resource:///modules/HUDService.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+
 /**
  * 'break' command
  */
 gcli.addCommand({
   name: "break",
   description: gcli.lookup("breakDesc"),
   manual: gcli.lookup("breakManual")
 });
@@ -25,22 +31,25 @@ gcli.addCommand({
 /**
  * 'break list' command
  */
 gcli.addCommand({
   name: "break list",
   description: gcli.lookup("breaklistDesc"),
   returnType: "html",
   exec: function(args, context) {
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+
     if (!dbg) {
       return gcli.lookup("breakaddDebuggerStopped");
     }
-    let breakpoints = dbg.breakpoints;
+
+    let breakpoints = dbg.getAllBreakpoints();
 
     if (Object.keys(breakpoints).length === 0) {
       return gcli.lookup("breaklistNone");
     }
 
     let reply = gcli.lookup("breaklistIntro");
     reply += "<ol>";
     for each (let breakpoint in breakpoints) {
@@ -71,21 +80,23 @@ gcli.addCommand({
   name: "break add line",
   description: gcli.lookup("breakaddlineDesc"),
   params: [
     {
       name: "file",
       type: {
         name: "selection",
         data: function() {
-          let win = HUDService.currentContext();
-          let dbg = win.DebuggerUI.getDebugger();
+          let gBrowser = HUDService.currentContext().gBrowser;
+          let target = TargetFactory.forTab(gBrowser.selectedTab);
+          let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+
           let files = [];
           if (dbg) {
-            let sourcesView = dbg.contentWindow.DebuggerView.Sources;
+            let sourcesView = dbg.panelWin.DebuggerView.Sources;
             for (let item in sourcesView) {
               files.push(item.value);
             }
           }
           return files;
         }
       },
       description: gcli.lookup("breakaddlineFileDesc")
@@ -94,18 +105,21 @@ gcli.addCommand({
       name: "line",
       type: { name: "number", min: 1, step: 10 },
       description: gcli.lookup("breakaddlineLineDesc")
     }
   ],
   returnType: "html",
   exec: function(args, context) {
     args.type = "line";
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
+
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+
     if (!dbg) {
       return gcli.lookup("breakaddDebuggerStopped");
     }
     var promise = context.createPromise();
     let position = { url: args.file, line: args.line };
     dbg.addBreakpoint(position, function(aBreakpoint, aError) {
       if (aError) {
         promise.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
@@ -126,37 +140,41 @@ gcli.addCommand({
   description: gcli.lookup("breakdelDesc"),
   params: [
     {
       name: "breakid",
       type: {
         name: "number",
         min: 0,
         max: function() {
-          let win = HUDService.currentContext();
-          let dbg = win.DebuggerUI.getDebugger();
+          let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+          let target = TargetFactory.forTab(gBrowser.selectedTab);
+          let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+
           if (!dbg) {
             return gcli.lookup("breakaddDebuggerStopped");
           }
-          return Object.keys(dbg.breakpoints).length - 1;
+          return Object.keys(dbg.getAllBreakpoints()).length - 1;
         },
       },
       description: gcli.lookup("breakdelBreakidDesc")
     }
   ],
   returnType: "html",
   exec: function(args, context) {
-    let win = HUDService.currentContext();
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+
     if (!dbg) {
       return gcli.lookup("breakaddDebuggerStopped");
     }
 
-    let breakpoints = dbg.breakpoints;
-    let id = Object.keys(dbg.breakpoints)[args.breakid];
+    let breakpoints = dbg.getAllBreakpoints();
+    let id = Object.keys(breakpoints)[args.breakid];
     if (!id || !(id in breakpoints)) {
       return gcli.lookup("breakNotFound");
     }
 
     let promise = context.createPromise();
     try {
       dbg.removeBreakpoint(breakpoints[id], function() {
         promise.resolve(gcli.lookup("breakdelRemoved"));
--- a/browser/devtools/commandline/CmdCalllog.jsm
+++ b/browser/devtools/commandline/CmdCalllog.jsm
@@ -4,29 +4,32 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 this.EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
   let JsDebugger = {};
   Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
 
   let global = Components.utils.getGlobalForObject({});
   JsDebugger.addDebuggerToGlobal(global);
 
   return global.Debugger;
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
+
 let debuggers = [];
 
 /**
  * 'calllog' command
  */
 gcli.addCommand({
   name: "calllog",
   description: gcli.lookup("calllogDesc")
@@ -45,18 +48,19 @@ gcli.addCommand({
     let dbg = new Debugger(contentWindow);
     dbg.onEnterFrame = function(frame) {
       // BUG 773652 -  Make the output from the GCLI calllog command nicer
       contentWindow.console.log("Method call: " + this.callDescription(frame));
     }.bind(this);
 
     debuggers.push(dbg);
 
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
-    HUDService.activateHUDForContext(tab);
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.openToolboxForTab(target, "webconsole");
 
     return gcli.lookup("calllogStartReply");
   },
 
   callDescription: function(frame) {
     let name = "<anonymous>";
     if (frame.callee.name) {
       name = frame.callee.name;
--- a/browser/devtools/commandline/CmdCalllogChrome.jsm
+++ b/browser/devtools/commandline/CmdCalllogChrome.jsm
@@ -5,18 +5,20 @@
 
 this.EXPORTED_SYMBOLS = [ ];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
   let JsDebugger = {};
   Cu.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
 
   let global = Components.utils.getGlobalForObject({});
   JsDebugger.addDebuggerToGlobal(global);
 
@@ -103,18 +105,19 @@ gcli.addCommand({
     debuggers.push(dbg);
 
     dbg.onEnterFrame = function(frame) {
       // BUG 773652 -  Make the output from the GCLI calllog command nicer
       contentWindow.console.log(gcli.lookup("callLogChromeMethodCall") +
                                 ": " + this.callDescription(frame));
     }.bind(this);
 
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab;
-    HUDService.activateHUDForContext(tab);
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.openToolboxForTab(target, "webconsole");
 
     return gcli.lookup("calllogChromeStartReply");
   },
 
   valueToString: function(value) {
     if (typeof value !== "object" || value === null)
       return uneval(value);
     return "[object " + value.class + "]";
--- a/browser/devtools/commandline/CmdConsole.jsm
+++ b/browser/devtools/commandline/CmdConsole.jsm
@@ -6,16 +6,20 @@ const { classes: Cc, interfaces: Ci, uti
 
 this.EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
                                   "resource:///modules/HUDService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
 
 /**
  * 'console' command
  */
 gcli.addCommand({
   name: "console",
   description: gcli.lookup("consoleDesc"),
   manual: gcli.lookup("consoleManual")
@@ -39,24 +43,26 @@ gcli.addCommand({
 
 /**
  * 'console close' command
  */
 gcli.addCommand({
   name: "console close",
   description: gcli.lookup("consolecloseDesc"),
   exec: function Command_consoleClose(args, context) {
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
-    HUDService.deactivateHUDForContext(tab);
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.closeToolbox(target);
   }
 });
 
 /**
  * 'console open' command
  */
 gcli.addCommand({
   name: "console open",
   description: gcli.lookup("consoleopenDesc"),
   exec: function Command_consoleOpen(args, context) {
-    let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab
-    HUDService.activateHUDForContext(tab);
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.openToolboxForTab(target, "webconsole");
   }
 });
--- a/browser/devtools/commandline/CmdDbg.jsm
+++ b/browser/devtools/commandline/CmdDbg.jsm
@@ -4,16 +4,21 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 this.EXPORTED_SYMBOLS = [ ];
 
 Cu.import("resource:///modules/devtools/gcli.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
+
 /**
  * 'dbg' command
  */
 gcli.addCommand({
   name: "dbg",
   description: gcli.lookup("dbgDesc"),
   manual: gcli.lookup("dbgManual")
 });
@@ -21,84 +26,76 @@ gcli.addCommand({
 /**
  * 'dbg open' command
  */
 gcli.addCommand({
   name: "dbg open",
   description: gcli.lookup("dbgOpen"),
   params: [],
   exec: function (args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let tab = win.gBrowser.selectedTab;
-    let dbg = win.DebuggerUI.findDebugger();
-
-    if (dbg) {
-      if (dbg.ownerTab !== tab) {
-        win.DebuggerUI.toggleDebugger();
-      }
-
-      return;
-    }
-
-    win.DebuggerUI.toggleDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    gDevTools.openToolboxForTab(target, "jsdebugger");
   }
 });
 
 /**
  * 'dbg close' command
  */
 gcli.addCommand({
   name: "dbg close",
   description: gcli.lookup("dbgClose"),
   params: [],
   exec: function (args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let tab = win.gBrowser.selectedTab;
-    let dbg = win.DebuggerUI.findDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
-    if (dbg) {
-      dbg.close();
+    if (dbg /* FIXME: and debugger panel is currently active */) {
+      gDevTools.closeToolbox(target);
     }
   }
 });
 
 /**
  * 'dbg interrupt' command
  */
 gcli.addCommand({
   name: "dbg interrupt",
   description: gcli.lookup("dbgInterrupt"),
   params: [],
   exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
     if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
+      let controller = dbg._controller;
       let thread = controller.activeThread;
       if (!thread.paused) {
         thread.interrupt();
       }
     }
   }
 });
 
 /**
  * 'dbg continue' command
  */
 gcli.addCommand({
   name: "dbg continue",
   description: gcli.lookup("dbgContinue"),
   params: [],
   exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
     if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
+      let controller = dbg._controller;
       let thread = controller.activeThread;
       if (thread.paused) {
         thread.resume();
       }
     }
   }
 });
 
@@ -116,62 +113,65 @@ gcli.addCommand({
 /**
  * 'dbg step over' command
  */
 gcli.addCommand({
   name: "dbg step over",
   description: gcli.lookup("dbgStepOverDesc"),
   params: [],
   exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
     if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
+      let controller = dbg._controller;
       let thread = controller.activeThread;
       if (thread.paused) {
         thread.stepOver();
       }
     }
   }
 });
 
 /**
  * 'dbg step in' command
  */
 gcli.addCommand({
   name: 'dbg step in',
   description: gcli.lookup("dbgStepInDesc"),
   params: [],
   exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
     if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
+      let controller = dbg._controller;
       let thread = controller.activeThread;
       if (thread.paused) {
         thread.stepIn();
       }
     }
   }
 });
 
 /**
  * 'dbg step over' command
  */
 gcli.addCommand({
   name: 'dbg step out',
   description: gcli.lookup("dbgStepOutDesc"),
   params: [],
   exec: function(args, context) {
-    let win = context.environment.chromeDocument.defaultView;
-    let dbg = win.DebuggerUI.getDebugger();
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
 
     if (dbg) {
-      let controller = dbg.contentWindow.DebuggerController;
+      let controller = dbg._controller;
       let thread = controller.activeThread;
       if (thread.paused) {
         thread.stepOut();
       }
     }
   }
 });
--- a/browser/devtools/commandline/Commands.jsm
+++ b/browser/devtools/commandline/Commands.jsm
@@ -19,8 +19,9 @@ Cu.import("resource:///modules/devtools/
 Cu.import("resource:///modules/devtools/CmdExport.jsm");
 Cu.import("resource:///modules/devtools/CmdInspect.jsm");
 Cu.import("resource:///modules/devtools/CmdJsb.jsm");
 Cu.import("resource:///modules/devtools/CmdPagemod.jsm");
 Cu.import("resource:///modules/devtools/CmdResize.jsm");
 Cu.import("resource:///modules/devtools/CmdRestart.jsm");
 Cu.import("resource:///modules/devtools/CmdScreenshot.jsm");
 Cu.import("resource:///modules/devtools/CmdTilt.jsm");
+Cu.import("resource:///modules/devtools/CmdScratchpad.jsm");
--- a/browser/devtools/commandline/test/browser_dbg_cmd.js
+++ b/browser/devtools/commandline/test/browser_dbg_cmd.js
@@ -1,82 +1,97 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+
 function test() {
   const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
                    "test/browser_dbg_cmd.html";
 
   DeveloperToolbarTest.test(TEST_URI, function() {
     testDbgCmd();
   });
 }
 
+function testCommands(dbg, cmd) {
+  // Wait for the initial resume...
+  dbg._controller.activeThread.addOneTimeListener("resumed", function () {
+    info("Starting tests.");
+
+    let contentDoc = content.window.document;
+    let output = contentDoc.querySelector("input[type=text]");
+    let btnDoit = contentDoc.querySelector("input[type=button]");
+
+    cmd("dbg interrupt", function() {
+      ok(true, "debugger is paused");
+      dbg._controller.activeThread.addOneTimeListener("resumed", function () {
+        ok(true, "debugger continued");
+        dbg._controller.activeThread.addOneTimeListener("paused", function() {
+          cmd("dbg step in", function() {
+            cmd("dbg step in", function() {
+              cmd("dbg step in", function() {
+                is(output.value, "step in", "debugger stepped in");
+                cmd("dbg step over", function() {
+                  is(output.value, "step over", "debugger stepped over");
+                  cmd("dbg step out", function() {
+                    is(output.value, "step out", "debugger stepped out");
+                    cmd("dbg continue", function() {
+                      cmd("dbg continue", function() {
+                        is(output.value, "dbg continue", "debugger continued");
+                        DeveloperToolbarTest.exec({
+                          typed: "dbg close",
+                          blankOutput: true
+                        });
+
+                        let target = TargetFactory.forTab(gBrowser.selectedTab);
+                        ok(!gDevTools.getToolboxForTarget(target),
+                          "Debugger was closed.");
+                        finish();
+                      });
+                    });
+                  });
+                });
+              });
+            });
+          });
+        });
+        EventUtils.sendMouseEvent({type:"click"}, btnDoit);
+      });
+      DeveloperToolbarTest.exec({
+        typed: "dbg continue",
+        blankOutput: true
+      });
+    });
+  });
+}
+
 function testDbgCmd() {
   DeveloperToolbarTest.exec({
     typed: "dbg open",
     blankOutput: true
   });
 
-  let pane = DebuggerUI.findDebugger();
-  ok(pane, "Debugger was opened.");
-  let frame = pane._frame;
-
-  frame.addEventListener("Debugger:Connected", function dbgConnected(aEvent) {
-    frame.removeEventListener("Debugger:Connected", dbgConnected, true);
-
-    // Wait for the initial resume...
-    aEvent.target.ownerDocument.defaultView.gClient
-        .addOneTimeListener("resumed", function() {
-
-      info("Starting tests.");
-
-      let contentDoc = content.window.document;
-      let output = contentDoc.querySelector("input[type=text]");
-      let btnDoit = contentDoc.querySelector("input[type=button]");
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = gDevTools.getToolboxForTarget(target);
 
-      cmd("dbg interrupt", function() {
-        ok(true, "debugger is paused");
-        pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
-          ok(true, "debugger continued");
-          pane.contentWindow.gClient.addOneTimeListener("paused", function() {
-            cmd("dbg step in", function() {
-              cmd("dbg step in", function() {
-                cmd("dbg step in", function() {
-                  is(output.value, "step in", "debugger stepped in");
-                  cmd("dbg step over", function() {
-                    is(output.value, "step over", "debugger stepped over");
-                    cmd("dbg step out", function() {
-                      is(output.value, "step out", "debugger stepped out");
-                      cmd("dbg continue", function() {
-                        cmd("dbg continue", function() {
-                          is(output.value, "dbg continue", "debugger continued");
-                          DeveloperToolbarTest.exec({
-                            typed: "dbg close",
-                            blankOutput: true
-                          });
-
-                          let dbg = DebuggerUI.findDebugger();
-                          ok(!dbg, "Debugger was closed.");
-                          finish();
-                        });
-                      });
-                    });
-                  });
-                });
-              });
-            });
-          });
-          EventUtils.sendMouseEvent({type:"click"}, btnDoit);
-        });
-        DeveloperToolbarTest.exec({
-          typed: "dbg continue",
-          blankOutput: true
-        });
-      });
-    });
+  toolbox.once("jsdebugger-ready", function dbgReady() {
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+    ok(dbg, "DebuggerPanel exists");
 
     function cmd(aTyped, aCallback) {
-      pane.contentWindow.gClient.addOneTimeListener("paused", aCallback);
+      dbg._controller.activeThread.addOneTimeListener("paused", aCallback);
       DeveloperToolbarTest.exec({
         typed: aTyped,
         blankOutput: true
       });
     }
+
+    if (dbg._controller.activeThread) {
+      testCommands(dbg, cmd);
+    } else {
+      dbg.once("connected", testCommands.bind(null, dbg, cmd));
+    }
   });
 }
--- a/browser/devtools/commandline/test/browser_dbg_cmd_break.js
+++ b/browser/devtools/commandline/test/browser_dbg_cmd_break.js
@@ -1,16 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the break command works as it should
 
 const TEST_URI = "http://example.com/browser/browser/devtools/commandline/" +
                  "test/browser_dbg_cmd_break.html";
 
+let tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+
 function test() {
   DeveloperToolbarTest.test(TEST_URI, [ testBreakCommands ]);
 }
 
 function testBreakCommands() {
   helpers.setInput('break');
   helpers.check({
     input:  'break',
@@ -30,91 +34,89 @@ function testBreakCommands() {
   helpers.setInput('break add line');
   helpers.check({
     input:  'break add line',
     hints:                ' <file> <line>',
     markup: 'VVVVVVVVVVVVVV',
     status: 'ERROR'
   });
 
-  let pane = DebuggerUI.toggleDebugger();
-
-  var dbgConnected = DeveloperToolbarTest.checkCalled(function() {
-    pane._frame.removeEventListener("Debugger:Connected", dbgConnected, true);
-
-    // Wait for the initial resume.
-    let client = pane.contentWindow.gClient;
-
-    var resumed = DeveloperToolbarTest.checkCalled(function() {
-
-      var framesAdded = DeveloperToolbarTest.checkCalled(function() {
-        helpers.setInput('break add line ' + TEST_URI + ' ' + content.wrappedJSObject.line0);
-        helpers.check({
-          hints: '',
-          status: 'VALID',
-          args: {
-            file: { value: TEST_URI },
-            line: { value: content.wrappedJSObject.line0 },
-          }
-        });
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let toolbox = gDevTools.openToolboxForTab(target, "jsdebugger");
+  toolbox.once("jsdebugger-ready", function dbgReady() {
+    let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+    ok(dbg, "DebuggerPanel exists");
+    dbg.once("connected", function() {
+      // Wait for the initial resume...
+      dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
+        dbg._view.Variables.lazyEmpty = false;
 
-        DeveloperToolbarTest.exec({
-          args: {
-            type: 'line',
-            file: TEST_URI,
-            line: content.wrappedJSObject.line0
-          },
-          completed: false
-        });
-
-        helpers.setInput('break list');
-        helpers.check({
-          input:  'break list',
-          hints:            '',
-          markup: 'VVVVVVVVVV',
-          status: 'VALID'
-        });
-
-        DeveloperToolbarTest.exec();
-
-        var cleanup = DeveloperToolbarTest.checkCalled(function() {
-          helpers.setInput('break del 9');
+        var client = dbg.panelWin.gClient;
+        var framesAdded = DeveloperToolbarTest.checkCalled(function() {
+          helpers.setInput('break add line ' + TEST_URI + ' ' + content.wrappedJSObject.line0);
           helpers.check({
-            input:  'break del 9',
-            hints:             '',
-            markup: 'VVVVVVVVVVE',
-            status: 'ERROR',
-            args: {
-              breakid: { status: 'ERROR', message: '9 is greater than maximum allowed: 0.' },
-            }
-          });
-
-          helpers.setInput('break del 0');
-          helpers.check({
-            input:  'break del 0',
-            hints:             '',
-            markup: 'VVVVVVVVVVV',
+            hints: '',
             status: 'VALID',
             args: {
-              breakid: { value: 0 },
+              file: { value: TEST_URI },
+              line: { value: content.wrappedJSObject.line0 },
             }
           });
 
           DeveloperToolbarTest.exec({
-            args: { breakid: 0 },
+            args: {
+              type: 'line',
+              file: TEST_URI,
+              line: content.wrappedJSObject.line0
+            },
             completed: false
           });
+
+          helpers.setInput('break list');
+          helpers.check({
+            input:  'break list',
+            hints:            '',
+            markup: 'VVVVVVVVVV',
+            status: 'VALID'
+          });
+
+          DeveloperToolbarTest.exec();
+
+          var cleanup = DeveloperToolbarTest.checkCalled(function() {
+            helpers.setInput('break del 9');
+            helpers.check({
+              input:  'break del 9',
+              hints:             '',
+              markup: 'VVVVVVVVVVE',
+              status: 'ERROR',
+              args: {
+                breakid: { status: 'ERROR', message: '9 is greater than maximum allowed: 0.' },
+              }
+            });
+
+            helpers.setInput('break del 0');
+            helpers.check({
+              input:  'break del 0',
+              hints:             '',
+              markup: 'VVVVVVVVVVV',
+              status: 'VALID',
+              args: {
+                breakid: { value: 0 },
+              }
+            });
+
+            DeveloperToolbarTest.exec({
+              args: { breakid: 0 },
+              completed: false
+            });
+          });
+
+          client.activeThread.resume(cleanup);
         });
 
-        client.activeThread.resume(cleanup);
-      });
-
-      client.activeThread.addOneTimeListener("framesadded", framesAdded);
+        client.activeThread.addOneTimeListener("framesadded", framesAdded);
 
-      // Trigger newScript notifications using eval.
-      content.wrappedJSObject.firstCall();
+        // Trigger newScript notifications using eval.
+        content.wrappedJSObject.firstCall();
+      });
     });
-
-    client.addOneTimeListener("resumed", resumed);
   });
-
-  pane._frame.addEventListener("Debugger:Connected", dbgConnected, true);
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/DebuggerPanel.jsm
@@ -0,0 +1,89 @@
+/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const Cu = Components.utils;
+
+this.EXPORTED_SYMBOLS = ["DebuggerPanel"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
+  "resource://gre/modules/devtools/dbg-server.jsm");
+
+function DebuggerPanel(iframeWindow, toolbox) {
+  this._toolbox = toolbox;
+  this._controller = iframeWindow.DebuggerController;
+  this._view = iframeWindow.DebuggerView;
+  this._controller._target = this.target;
+  this._bkp = this._controller.Breakpoints;
+  this.panelWin = iframeWindow;
+
+  this._ensureOnlyOneRunningDebugger();
+  if (!this.target.isRemote) {
+    if (!DebuggerServer.initialized) {
+      DebuggerServer.init();
+      DebuggerServer.addBrowserActors();
+    }
+  }
+
+  let onDebuggerLoaded = function () {
+    iframeWindow.removeEventListener("Debugger:Loaded", onDebuggerLoaded, true);
+    this.setReady();
+  }.bind(this);
+
+  let onDebuggerConnected = function () {
+    iframeWindow.removeEventListener("Debugger:Connected",
+      onDebuggerConnected, true);
+    this.emit("connected");
+  }.bind(this);
+
+  iframeWindow.addEventListener("Debugger:Loaded", onDebuggerLoaded, true);
+  iframeWindow.addEventListener("Debugger:Connected",
+    onDebuggerConnected, true);
+
+  new EventEmitter(this);
+}
+
+DebuggerPanel.prototype = {
+  // DevToolPanel API
+  get target() this._toolbox.target,
+
+  get isReady() this._isReady,
+
+  setReady: function() {
+    this._isReady = true;
+    this.emit("ready");
+  },
+
+  destroy: function() {
+  },
+
+  // DebuggerPanel API
+
+  addBreakpoint: function() {
+    this._bkp.addBreakpoint.apply(this._bkp, arguments);
+  },
+
+  removeBreakpoint: function() {
+    this._bkp.removeBreakpoint.apply(this._bkp, arguments);
+  },
+
+  getBreakpoint: function() {
+    return this._bkp.getBreakpoint.apply(this._bkp, arguments);
+  },
+
+  getAllBreakpoints: function() {
+    return this._bkp.store;
+  },
+
+  // Private
+
+  _ensureOnlyOneRunningDebugger: function() {
+    // FIXME
+  },
+};
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -43,16 +43,17 @@ let DebuggerController = {
   /**
    * Initializes the view and connects a debugger client to the server.
    */
   _startupDebugger: function DC__startupDebugger() {
     if (this._isInitialized) {
       return;
     }
     this._isInitialized = true;
+
     window.removeEventListener("load", this._startupDebugger, true);
 
     DebuggerView.initialize(function() {
       DebuggerView._isInitialized = true;
 
       window.dispatchEvent("Debugger:Loaded");
       this._connect();
     }.bind(this));
@@ -140,54 +141,76 @@ let DebuggerController = {
       Prefs.remoteHost + ":" + Prefs.remotePort);
   },
 
   /**
    * Initializes a debugger client and connects it to the debugger server,
    * wiring event handlers as necessary.
    */
   _connect: function DC__connect() {
-    if (window._isRemoteDebugger && !this._prepareConnection()) {
+    function callback() {
+      window.dispatchEvent("Debugger:Connected");
+    }
+
+    let client;
+    // Remote debugging gets the debuggee from a RemoteTarget object.
+    if (this._target && this._target.isRemote) {
+      client = this.client = this._target.client;
+
+      this._target.on("close", this._onTabDetached);
+      this._target.on("navigate", this._onTabNavigated);
+
+      if (this._target.chrome) {
+        let dbg = this._target.form.chromeDebugger;
+        this._startChromeDebugging(client, dbg, callback);
+      } else {
+        this._startDebuggingTab(client, this._target.form, callback);
+      }
       return;
     }
-    let transport = (window._isChromeDebugger || window._isRemoteDebugger)
+
+    // Content debugging can connect directly to the page.
+    // TODO: convert this to use a TabTarget.
+    let transport = window._isChromeDebugger
       ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
       : DebuggerServer.connectPipe();
+    client = this.client = new DebuggerClient(transport);
 
-    let client = this.client = new DebuggerClient(transport);
     client.addListener("tabNavigated", this._onTabNavigated);
     client.addListener("tabDetached", this._onTabDetached);
 
     client.connect(function(aType, aTraits) {
       client.listTabs(function(aResponse) {
         if (window._isChromeDebugger) {
           let dbg = aResponse.chromeDebugger;
-          this._startChromeDebugging(client, dbg);
+          this._startChromeDebugging(client, dbg, callback);
         } else {
           let tab = aResponse.tabs[aResponse.selected];
-          this._startDebuggingTab(client, tab);
+          this._startDebuggingTab(client, tab, callback);
         }
-        window.dispatchEvent("Debugger:Connected");
       }.bind(this));
     }.bind(this));
   },
 
   /**
    * Disconnects the debugger client and removes event handlers as necessary.
    */
   _disconnect: function DC__disconnect() {
     // Return early if the client didn't even have a chance to instantiate.
     if (!this.client) {
       return;
     }
     this.client.removeListener("tabNavigated", this._onTabNavigated);
     this.client.removeListener("tabDetached", this._onTabDetached);
-    this.client.close();
 
-    this.client = null;
+    if (!this._target.isRemote) {
+      this.client.close();
+      this.client = null;
+    }
+
     this.tabClient = null;
     this.activeThread = null;
   },
 
   /**
    * Called for each location change in the debugged tab.
    */
   _onTabNavigated: function DC__onTabNavigated() {
@@ -207,17 +230,18 @@ let DebuggerController = {
   /**
    * Sets up a debugging session.
    *
    * @param DebuggerClient aClient
    *        The debugger client.
    * @param object aTabGrip
    *        The remote protocol grip of the tab.
    */
-  _startDebuggingTab: function DC__startDebuggingTab(aClient, aTabGrip) {
+  _startDebuggingTab: function DC__startDebuggingTab
+      (aClient, aTabGrip, aCallback=function(){}) {
     if (!aClient) {
       Cu.reportError("No client found!");
       return;
     }
     this.client = aClient;
 
     aClient.attachTab(aTabGrip.actor, function(aResponse, aTabClient) {
       if (!aTabClient) {
@@ -233,29 +257,31 @@ let DebuggerController = {
         }
         this.activeThread = aThreadClient;
 
         this.ThreadState.connect();
         this.StackFrames.connect();
         this.SourceScripts.connect();
         aThreadClient.resume();
 
+        aCallback();
       }.bind(this));
     }.bind(this));
   },
 
   /**
    * Sets up a chrome debugging session.
    *
    * @param DebuggerClient aClient
    *        The debugger client.
    * @param object aChromeDebugger
    *        The remote protocol grip of the chrome debugger.
    */
-  _startChromeDebugging: function DC__startChromeDebugging(aClient, aChromeDebugger) {
+  _startChromeDebugging: function DC__startChromeDebugging
+      (aClient, aChromeDebugger, aCallback=function(){}) {
     if (!aClient) {
       Cu.reportError("No client found!");
       return;
     }
     this.client = aClient;
 
     aClient.attachThread(aChromeDebugger, function(aResponse, aThreadClient) {
       if (!aThreadClient) {
@@ -264,16 +290,17 @@ let DebuggerController = {
       }
       this.activeThread = aThreadClient;
 
       this.ThreadState.connect();
       this.StackFrames.connect();
       this.SourceScripts.connect();
       aThreadClient.resume();
 
+      aCallback();
     }.bind(this));
   },
 
   /**
    * Attempts to quit the current process if allowed.
    */
   _quitApp: function DC__quitApp() {
     let canceled = Cc["@mozilla.org/supports-PRBool;1"]
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -20,17 +20,16 @@ function ToolbarView() {
 }
 
 ToolbarView.prototype = {
   /**
    * Initialization function, called when the debugger is started.
    */
   initialize: function DVT_initialize() {
     dumpn("Initializing the ToolbarView");
-    this._closeButton = document.getElementById("close");
     this._togglePanesButton = document.getElementById("toggle-panes");
     this._resumeButton = document.getElementById("resume");
     this._stepOverButton = document.getElementById("step-over");
     this._stepInButton = document.getElementById("step-in");
     this._stepOutButton = document.getElementById("step-out");
     this._chromeGlobals = document.getElementById("chrome-globals");
     this._scripts = document.getElementById("sources");
 
@@ -39,56 +38,43 @@ ToolbarView.prototype = {
     let stepInKey = LayoutHelpers.prettyKey(document.getElementById("stepInKey"), true);
     let stepOutKey = LayoutHelpers.prettyKey(document.getElementById("stepOutKey"), true);
     this._resumeTooltip = L10N.getFormatStr("resumeButtonTooltip", [resumeKey]);
     this._pauseTooltip = L10N.getFormatStr("pauseButtonTooltip", [resumeKey]);
     this._stepOverTooltip = L10N.getFormatStr("stepOverTooltip", [stepOverKey]);
     this._stepInTooltip = L10N.getFormatStr("stepInTooltip", [stepInKey]);
     this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", [stepOutKey]);
 
-    this._closeButton.addEventListener("click", this._onCloseClick, false);
     this._togglePanesButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
     this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
     this._stepOverButton.addEventListener("mousedown", this._onStepOverPressed, false);
     this._stepInButton.addEventListener("mousedown", this._onStepInPressed, false);
     this._stepOutButton.addEventListener("mousedown", this._onStepOutPressed, false);
 
     this._stepOverButton.setAttribute("tooltiptext", this._stepOverTooltip);
     this._stepInButton.setAttribute("tooltiptext", this._stepInTooltip);
     this._stepOutButton.setAttribute("tooltiptext", this._stepOutTooltip);
 
-    this.toggleCloseButton(!window._isRemoteDebugger && !window._isChromeDebugger);
     // TODO: bug 806775
     // this.toggleChromeGlobalsContainer(window._isChromeDebugger);
   },
 
   /**
    * Destruction function, called when the debugger is closed.
    */
   destroy: function DVT_destroy() {
     dumpn("Destroying the ToolbarView");
-    this._closeButton.removeEventListener("click", this._onCloseClick, false);
     this._togglePanesButton.removeEventListener("mousedown", this._onTogglePanesPressed, false);
     this._resumeButton.removeEventListener("mousedown", this._onResumePressed, false);
     this._stepOverButton.removeEventListener("mousedown", this._onStepOverPressed, false);
     this._stepInButton.removeEventListener("mousedown", this._onStepInPressed, false);
     this._stepOutButton.removeEventListener("mousedown", this._onStepOutPressed, false);
   },
 
   /**
-   * Sets the close button hidden or visible. It's hidden by default.
-   *
-   * @param boolean aVisibleFlag
-   *        Specifies the intended visibility.
-   */
-  toggleCloseButton: function DVT_toggleCloseButton(aVisibleFlag) {
-    this._closeButton.setAttribute("hidden", !aVisibleFlag);
-  },
-
-  /**
    * Sets the resume button state based on the debugger active thread.
    *
    * @param string aState
    *        Either "paused" or "attached".
    */
   toggleResumeButtonState: function DVT_toggleResumeButtonState(aState) {
     // If we're paused, check and show a resume label on the button.
     if (aState == "paused") {
@@ -172,17 +158,16 @@ ToolbarView.prototype = {
    * Listener handling the step out button click event.
    */
   _onStepOutPressed: function DVT__onStepOutPressed() {
     if (DebuggerController.activeThread.paused) {
       DebuggerController.activeThread.stepOut();
     }
   },
 
-  _closeButton: null,
   _togglePanesButton: null,
   _resumeButton: null,
   _stepOverButton: null,
   _stepInButton: null,
   _stepOutButton: null,
   _chromeGlobals: null,
   _sources: null,
   _resumeTooltip: "",
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -169,21 +169,16 @@
     <key id="addConditionalBreakpointKey"
          key="&debuggerUI.seMenuCondBreak.key;"
          modifiers="accel shift"
          command="addConditionalBreakpointCommand"/>
   </keyset>
 
   <vbox id="body" flex="1">
     <toolbar id="dbg-toolbar" class="devtools-toolbar">
-#ifdef XP_MACOSX
-      <toolbarbutton id="close"
-                     class="devtools-closebutton"
-                     tooltiptext="&debuggerUI.closeButton.tooltip;"/>
-#endif
       <hbox id="debugger-controls">
         <toolbarbutton id="resume"
                        class="devtools-toolbarbutton"
                        tabindex="0"/>
         <toolbarbutton id="step-over"
                        class="devtools-toolbarbutton"
                        tabindex="0"/>
         <toolbarbutton id="step-in"
@@ -203,21 +198,16 @@
       <toolbarbutton id="toggle-panes"
                      class="devtools-toolbarbutton"
                      tooltiptext="&debuggerUI.panesButton.tooltip;"
                      tabindex="0"/>
       <toolbarbutton id="debugger-options"
                      class="devtools-option-toolbarbutton"
                      tooltiptext="&debuggerUI.optsButton.tooltip;"
                      popup="debuggerPrefsContextMenu"/>
-#ifndef XP_MACOSX
-      <toolbarbutton id="close"
-                     class="devtools-closebutton"
-                     tooltiptext="&debuggerUI.closeButton.tooltip;"/>
-#endif
     </toolbar>
 
     <panel id="searchbox-panel"
            type="arrow"
            noautofocus="true"
            position="before_start">
       <vbox>
         <label class="description" value="&debuggerUI.searchPanelTitle;"/>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -8,18 +8,18 @@ srcdir          = @srcdir@
 VPATH           = @srcdir@
 relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_leaktest.js \
 	browser_dbg_createChrome.js \
-	browser_dbg_debugger-tab-switch.js \
-	browser_dbg_debugger-tab-switch-window.js \
+	$(browser_dbg_debugger-tab-switch.js disabled until issues 106, 40 are fixed) \
+	$(browser_dbg_debugger-tab-switch-window.js disabled until issues 106, 40 are fixed) \
 	browser_dbg_debuggerstatement.js \
 	browser_dbg_listtabs.js \
 	browser_dbg_tabactor-01.js \
 	browser_dbg_tabactor-02.js \
 	browser_dbg_globalactor-01.js \
 	testactors.js \
 	browser_dbg_nav-01.js \
 	browser_dbg_propertyview-01.js \
@@ -42,17 +42,16 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_propertyview-filter-05.js \
 	browser_dbg_propertyview-filter-06.js \
 	browser_dbg_propertyview-filter-07.js \
 	browser_dbg_propertyview-filter-08.js \
 	browser_dbg_propertyview-reexpand.js \
 	browser_dbg_reload-same-script.js \
 	browser_dbg_reload-preferred-script.js \
 	browser_dbg_pane-collapse.js \
-	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_location-changes-new.js \
@@ -79,17 +78,16 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_bug727429_watch-expressions-01.js \
 	browser_dbg_bug727429_watch-expressions-02.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
 	browser_dbg_bug786070_hide_nonenums.js \
 	browser_dbg_displayName.js \
 	browser_dbg_iframes.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
-	browser_dbg_menustatus.js \
 	browser_dbg_bfcache.js \
 	browser_dbg_breakpoint-new-script.js \
 	browser_dbg_bug737803_editor_actual_location.js \
 	browser_dbg_progress-listener-bug.js \
 	browser_dbg_chrome-debugging.js \
 	$(filter disabled-for-intermittent-failures--bug-753225, browser_dbg_createRemote.js) \
 	head.js \
 	$(NULL)
--- a/browser/devtools/debugger/test/browser_dbg_bfcache.js
+++ b/browser/devtools/debugger/test/browser_dbg_bfcache.js
@@ -15,17 +15,17 @@ var gDebugger = null;
 var gScripts = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testInitialLoad();
   });
 }
 
 function testInitialLoad() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_breakpoint-new-script.js
+++ b/browser/devtools/debugger/test/browser_dbg_breakpoint-new-script.js
@@ -12,17 +12,17 @@ var gTab = null;
 var gDebugger = null;
 var gDebuggee = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     testAddBreakpoint();
   });
 }
 
 function testAddBreakpoint()
 {
--- a/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
@@ -26,41 +26,41 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
+    gDebugger.addEventListener("Debugger:SourceShown", onScriptShown);
+
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function() {
       gDebuggee.firstCall();
     });
   });
 
   function onScriptShown(aEvent)
   {
     scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
     executeSoon(startTest);
   }
 
-  window.addEventListener("Debugger:SourceShown", onScriptShown);
-
   function startTest()
   {
     if (scriptShown && framesAdded && resumed && !testStarted) {
-      window.removeEventListener("Debugger:SourceShown", onScriptShown);
+      gDebugger.removeEventListener("Debugger:SourceShown", onScriptShown);
       testStarted = true;
       Services.tm.currentThread.dispatch({ run: performTest }, 0);
     }
   }
 
   function performTest()
   {
     gScripts = gDebugger.DebuggerView.Sources;
@@ -72,17 +72,17 @@ function test()
 
     gEditor = gDebugger.editor;
 
     isnot(gEditor.getText().indexOf("debugger"), -1,
           "The correct script was loaded initially.");
     isnot(gScripts.selectedValue, gScripts.values[0],
           "the correct script is selected");
 
-    gBreakpoints = gPane.breakpoints;
+    gBreakpoints = gPane.getAllBreakpoints();
     is(Object.keys(gBreakpoints), 0, "no breakpoints");
     ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
 
     is(gEditor.getBreakpoints().length, 0, "no breakpoints in the editor");
 
     gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
                              onEditorBreakpointAddFirst);
     let location = {url: gScripts.selectedValue, line: 6};
@@ -122,17 +122,17 @@ function test()
        "breakpoint1 client line is correct");
 
     executeSoon(function() {
       ok(aBreakpointClient.actor in gBreakpoints,
          "breakpoint1 client found in the list of debugger breakpoints");
       is(Object.keys(gBreakpoints).length, 1,
          "the list of debugger breakpoints holds only one breakpoint");
       is(gPane.getBreakpoint(gScripts.selectedValue, 6), aBreakpointClient,
-         "getBreakpoint(selectedScript, 2) returns the correct breakpoint");
+         "getBreakpoint returns the correct breakpoint");
 
       info("remove the first breakpoint");
       gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
                                onEditorBreakpointRemoveFirst);
       gPane.removeBreakpoint(aBreakpointClient, onBreakpointRemoveFirst);
     });
   }
 
--- a/browser/devtools/debugger/test/browser_dbg_bug723071_editor-breakpoints-pane.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug723071_editor-breakpoints-pane.js
@@ -24,41 +24,41 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
+    gDebugger.addEventListener("Debugger:SourceShown", onScriptShown);
+
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function() {
       gDebuggee.firstCall();
     });
   });
 
   function onScriptShown(aEvent)
   {
     scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
     executeSoon(startTest);
   }
 
-  window.addEventListener("Debugger:SourceShown", onScriptShown);
-
   function startTest()
   {
     if (scriptShown && framesAdded && resumed && !testStarted) {
-      window.removeEventListener("Debugger:SourceShown", onScriptShown);
+      gDebugger.removeEventListener("Debugger:SourceShown", onScriptShown);
       testStarted = true;
       Services.tm.currentThread.dispatch({ run: performTest }, 0);
     }
   }
 
   let breakpointsAdded = 0;
   let breakpointsDisabled = 0;
   let breakpointsRemoved = 0;
@@ -74,17 +74,17 @@ function test()
 
     let editor = gDebugger.editor;
 
     isnot(editor.getText().indexOf("debugger"), -1,
           "The correct script was loaded initially.");
     isnot(gScripts.selectedValue, gScripts.values[0],
           "the correct script is selected");
 
-    gBreakpoints = gPane.breakpoints;
+    gBreakpoints = gPane.getAllBreakpoints();
     is(Object.keys(gBreakpoints), 0, "no breakpoints");
     ok(!gPane.getBreakpoint("chocolate", 3), "getBreakpoint('chocolate', 3) returns falsey");
 
     is(editor.getBreakpoints().length, 0, "no breakpoints in the editor");
 
     gBreakpointsContainer = gDebugger.DebuggerView.Breakpoints;
     gBreakpointsParent = gBreakpointsContainer._container._parent;
     gBreakpointsList = gBreakpointsContainer._container._list;
--- a/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-01.js
@@ -14,17 +14,17 @@ let gDebugger = null;
 let gWatch = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
 
     gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
 
     executeSoon(function() {
       performTest();
     });
   });
--- a/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug727429_watch-expressions-02.js
@@ -15,17 +15,17 @@ let gWatch = null;
 let gVars = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
     gVars = gDebugger.DebuggerView.Variables;
 
     gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
     addExpressions();
     performTest();
   });
 
--- a/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js
@@ -23,17 +23,17 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_bug737803_editor_actual_location.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug737803_editor_actual_location.js
@@ -25,48 +25,48 @@ function test() {
   let framesAdded = false;
   let testStarted = false;
   let resumed = false;
 
   debug_tab_pane(TAB_URL, function (aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
     gDebuggee = aDebuggee;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
+    gDebugger.addEventListener("Debugger:SourceShown", onScriptShown);
+
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function () {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function () {
       gDebuggee.firstCall();
     });
   });
 
   function onScriptShown(aEvent) {
     scriptShown = aEvent.detail.url.indexOf("-02.js") != -1;
     executeSoon(startTest);
   }
 
-  window.addEventListener("Debugger:SourceShown", onScriptShown);
-
   function startTest() {
     if (scriptShown && framesAdded && resumed && !testStarted) {
-      window.removeEventListener("Debugger:SourceShown", onScriptShown);
+      gDebugger.removeEventListener("Debugger:SourceShown", onScriptShown);
       testStarted = true;
       Services.tm.currentThread.dispatch({ run: performTest }, 0);
     }
   }
 
   function performTest() {
     gScripts = gDebugger.DebuggerView.Sources;
     gEditor = gDebugger.editor;
-    gBreakpoints = gPane.breakpoints;
+    gBreakpoints = gPane.getAllBreakpoints();
     is(Object.keys(gBreakpoints), 0, "There are no breakpoints");
 
     gEditor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE,
       onEditorBreakpointAdd);
 
     let location = { url: gScripts.selectedValue, line: 4 };
     executeSoon(function () {
       gPane.addBreakpoint(location, onBreakpointAdd);
--- a/browser/devtools/debugger/test/browser_dbg_bug740825_conditional-breakpoints-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug740825_conditional-breakpoints-01.js
@@ -24,17 +24,17 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gBreakpoints = gDebugger.DebuggerController.Breakpoints;
     gBreakpointsPane = gDebugger.DebuggerView.Breakpoints;
 
     gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
@@ -74,17 +74,17 @@ function test()
 
     gEditor = gDebugger.editor;
 
     isnot(gEditor.getText().indexOf("ermahgerd"), -1,
           "The correct script was loaded initially.");
     is(gScripts.selectedValue, gScripts.values[0],
           "The correct script is selected");
 
-    gBreakpoints = gPane.breakpoints;
+    gBreakpoints = gPane.getAllBreakpoints();
     is(Object.keys(gBreakpoints).length, 13, "thirteen breakpoints");
     ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
 
     is(gEditor.getBreakpoints().length, 13, "thirteen breakpoints in the editor");
 
     executeSoon(test1);
   }
 
--- a/browser/devtools/debugger/test/browser_dbg_bug740825_conditional-breakpoints-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug740825_conditional-breakpoints-02.js
@@ -28,17 +28,17 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gBreakpoints = gDebugger.DebuggerController.Breakpoints;
     gBreakpointsPane = gDebugger.DebuggerView.Breakpoints;
 
     gDebugger.DebuggerView.togglePanes({ visible: true, animated: false });
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
@@ -78,17 +78,17 @@ function test()
 
     gEditor = gDebugger.editor;
 
     isnot(gEditor.getText().indexOf("ermahgerd"), -1,
           "The correct script was loaded initially.");
     is(gScripts.selectedValue, gScripts.values[0],
           "The correct script is selected");
 
-    gBreakpoints = gPane.breakpoints;
+    gBreakpoints = gPane.getAllBreakpoints();
     is(Object.keys(gBreakpoints), 0, "no breakpoints");
     ok(!gPane.getBreakpoint("foo", 3), "getBreakpoint('foo', 3) returns falsey");
 
     is(gEditor.getBreakpoints().length, 0, "no breakpoints in the editor");
 
     executeSoon(addBreakpoint1);
   }
 
--- a/browser/devtools/debugger/test/browser_dbg_bug786070_hide_nonenums.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug786070_hide_nonenums.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testNonEnumProperties();
   });
 }
 
 function testNonEnumProperties() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_clean-exit.js
+++ b/browser/devtools/debugger/test/browser_dbg_clean-exit.js
@@ -10,17 +10,17 @@ var gTab = null;
 var gDebugger = null;
 
 const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test() {
   debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testCleanExit();
   });
 }
 
 function testCleanExit() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js
+++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js
@@ -13,17 +13,17 @@ var gRemoteTimeout = null;
 var gAutoConnect = null;
 
 const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
 
 function test() {
   debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
     gTab = aTab;
     gWindow = aWindow;
-    let gDebugger = gWindow.contentWindow;
+    let gDebugger = gWindow.panelWin;
 
     info("Current remote window x: " +
       Services.prefs.getIntPref("devtools.debugger.ui.win-x"));
     info("Current remote window y: " +
       Services.prefs.getIntPref("devtools.debugger.ui.win-y"));
     info("Current remote window width: " +
       Services.prefs.getIntPref("devtools.debugger.ui.win-width"));
     info("Current remote window height: " +
--- a/browser/devtools/debugger/test/browser_dbg_displayName.js
+++ b/browser/devtools/debugger/test/browser_dbg_displayName.js
@@ -13,17 +13,17 @@ var gDebugger = null;
 
 const TAB_URL = EXAMPLE_URL + "browser_dbg_displayName.html";
 
 function test() {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testAnonCall();
   });
 }
 
 function testAnonCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_iframes.js
+++ b/browser/devtools/debugger/test/browser_dbg_iframes.js
@@ -9,20 +9,17 @@ var gPane = null;
 var gTab = null;
 
 const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
 
 function test() {
   debug_tab_pane(TEST_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    let gDebugger = gPane.contentWindow;
-
-    is(gDebugger.document.getElementById("close").getAttribute("hidden"), "false",
-      "The close button should be visible in a normal content debugger.");
+    let gDebugger = gPane.panelWin;
 
     is(gDebugger.DebuggerController.activeThread.paused, false,
       "Should be running after debug_tab_pane.");
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       Services.tm.currentThread.dispatch({ run: function() {
 
         let frames = gDebugger.DebuggerView.StackFrames._container._list;
--- a/browser/devtools/debugger/test/browser_dbg_leaktest.js
+++ b/browser/devtools/debugger/test/browser_dbg_leaktest.js
@@ -19,17 +19,17 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-blank.js
@@ -15,17 +15,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.simpleCall();
   });
--- a/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js
@@ -15,17 +15,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.simpleCall();
   });
--- a/browser/devtools/debugger/test/browser_dbg_location-changes.js
+++ b/browser/devtools/debugger/test/browser_dbg_location-changes.js
@@ -12,17 +12,17 @@ var gDebuggee = null;
 var gDebugger = null;
 
 function test()
 {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({
--- a/browser/devtools/debugger/test/browser_dbg_pane-collapse.js
+++ b/browser/devtools/debugger/test/browser_dbg_pane-collapse.js
@@ -11,17 +11,17 @@ var gDebuggee = null;
 var gDebugger = null;
 var gView = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gView = gDebugger.DebuggerView;
 
     testPanesState();
 
     gView.togglePanes({ visible: true, animated: false });
     testPaneCollapse1();
     testPaneCollapse2();
     testPanesStartupPref(closeDebuggerAndFinish);
--- a/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
+++ b/browser/devtools/debugger/test/browser_dbg_panesize-inner.js
@@ -2,70 +2,75 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 function test() {
   var tab1 = addTab(TAB1_URL, function() {
     gBrowser.selectedTab = tab1;
+    let target1 = TargetFactory.forTab(tab1);
 
-    ok(!DebuggerUI.getDebugger(),
-      "Shouldn't have a debugger pane for this tab yet.");
+    ok(!gDevTools.getPanelForTarget("jsdebugger", target1),
+      "Shouldn't have a debugger panel for this tab yet.");
 
-    let pane = DebuggerUI.toggleDebugger();
-    ok(pane, "toggleDebugger() should return a pane.");
+    let toolbox = gDevTools.openToolboxForTab(target1, "jsdebugger");
+    toolbox.once("jsdebugger-ready", function dbgReady() {
+      let dbg = gDevTools.getPanelForTarget("jsdebugger", target1);
+      ok(dbg, "We should have a debugger panel.");
 
-    let preferredSfw = Services.prefs.getIntPref("devtools.debugger.ui.stackframes-width");
-    let preferredBpw = Services.prefs.getIntPref("devtools.debugger.ui.variables-width");
-    let someWidth1, someWidth2;
+      let preferredSfw = Services.prefs.getIntPref("devtools.debugger.ui.stackframes-width");
+      let preferredBpw = Services.prefs.getIntPref("devtools.debugger.ui.variables-width");
+      let someWidth1, someWidth2;
 
-    do {
-      someWidth1 = parseInt(Math.random() * 200) + 100;
-      someWidth2 = parseInt(Math.random() * 200) + 100;
-    } while (someWidth1 == preferredSfw ||
-             someWidth2 == preferredBpw)
+      do {
+        someWidth1 = parseInt(Math.random() * 200) + 100;
+        someWidth2 = parseInt(Math.random() * 200) + 100;
+      } while (someWidth1 == preferredSfw ||
+               someWidth2 == preferredBpw)
+
+      let someWidth1 = parseInt(Math.random() * 200) + 100;
+      let someWidth2 = parseInt(Math.random() * 200) + 100;
 
-    info("Preferred stackframes width: " + preferredSfw);
-    info("Preferred variables width: " + preferredBpw);
-    info("Generated stackframes width: " + someWidth1);
-    info("Generated variables width: " + someWidth2);
+      info("Preferred stackframes width: " + preferredSfw);
+      info("Preferred variables width: " + preferredBpw);
+      info("Generated stackframes width: " + someWidth1);
+      info("Generated variables width: " + someWidth2);
+
+      let content = dbg.panelWin;
+      let stackframes;
+      let variables;
 
-    is(DebuggerUI.getDebugger(), pane,
-      "getDebugger() should return the same pane as toggleDebugger().");
+      wait_for_connect_and_resume(function() {
+        ok(content.Prefs.stackframesWidth,
+          "The debugger preferences should have a saved stackframesWidth value.");
+        ok(content.Prefs.variablesWidth,
+          "The debugger preferences should have a saved variablesWidth value.");
 
-    let content = pane.contentWindow;
-    let stackframes;
-    let variables;
+        stackframes = content.document.getElementById("stackframes+breakpoints");
+        variables = content.document.getElementById("variables+expressions");
 
-    wait_for_connect_and_resume(function() {
-      ok(content.Prefs.stackframesWidth,
-        "The debugger preferences should have a saved stackframesWidth value.");
-      ok(content.Prefs.variablesWidth,
-        "The debugger preferences should have a saved variablesWidth value.");
+        is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
+          "The stackframes pane width should be the same as the preferred value.");
+        is(content.Prefs.variablesWidth, variables.getAttribute("width"),
+          "The variables pane width should be the same as the preferred value.");
 
-      stackframes = content.document.getElementById("stackframes+breakpoints");
-      variables = content.document.getElementById("variables+expressions");
+        stackframes.setAttribute("width", someWidth1);
+        variables.setAttribute("width", someWidth2);
+
+        removeTab(tab1);
+      }, tab1);
+
+      window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
+        window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
 
-      is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
-        "The stackframes pane width should be the same as the preferred value.");
-      is(content.Prefs.variablesWidth, variables.getAttribute("width"),
-        "The variables pane width should be the same as the preferred value.");
+        is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
+          "The stackframes pane width should have been saved by now.");
+        is(content.Prefs.variablesWidth, variables.getAttribute("width"),
+          "The variables pane width should have been saved by now.");
 
-      stackframes.setAttribute("width", someWidth1);
-      variables.setAttribute("width", someWidth2);
+        finish();
 
-      removeTab(tab1);
+      }, true);
     });
 
-    window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
-      window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
-
-      is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
-        "The stackframes pane width should have been saved by now.");
-      is(content.Prefs.variablesWidth, variables.getAttribute("width"),
-        "The variables pane width should have been saved by now.");
-
-      finish();
-
-    }, true);
   });
 }
deleted file mode 100644
--- a/browser/devtools/debugger/test/browser_dbg_panesize.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-function test() {
-  var tab1 = addTab(TAB1_URL, function() {
-    gBrowser.selectedTab = tab1;
-
-    ok(!DebuggerUI.getDebugger(),
-      "Shouldn't have a debugger pane for this tab yet.");
-
-    let pane = DebuggerUI.toggleDebugger();
-    ok(pane, "toggleDebugger() should return a pane.");
-
-    let preferredHeight = Services.prefs.getIntPref("devtools.debugger.ui.height");
-    let someHeight;
-
-    do {
-      someHeight = parseInt(Math.random() * 200) + 200;
-    } while (someHeight == preferredHeight)
-
-    info("Preferred pane height: " + preferredHeight);
-    info("Generated pane height: " + someHeight);
-
-    is(DebuggerUI.getDebugger(), pane,
-      "getDebugger() should return the same pane as toggleDebugger().");
-
-    ok(DebuggerUI.preferences.height,
-      "The debugger preferences should have a saved height value.");
-
-    is(DebuggerUI.preferences.height, pane._frame.height,
-      "The debugger pane height should be the same as the preferred value.");
-
-    pane._frame.height = someHeight;
-
-    ok(DebuggerUI.preferences.height !== someHeight,
-      "Height preferences shouldn't have been updated yet.");
-
-    wait_for_connect_and_resume(function() {
-      removeTab(tab1);
-    });
-
-    window.addEventListener("Debugger:Shutdown", function dbgShutdown() {
-      window.removeEventListener("Debugger:Shutdown", dbgShutdown, true);
-
-      is(DebuggerUI.preferences.height, someHeight,
-        "Height preferences should have been updated by now.");
-
-      finish();
-
-    }, true);
-  });
-}
--- a/browser/devtools/debugger/test/browser_dbg_pause-exceptions.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-exceptions.js
@@ -15,27 +15,27 @@ var gCount = 0;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.nonEnumVisible = false;
     testWithFrame();
   });
 }
 
 function testWithFrame()
 {
-  gPane.contentWindow.gClient.addOneTimeListener("paused", function() {
+  gPane.panelWin.gClient.addOneTimeListener("paused", function() {
     gDebugger.addEventListener("Debugger:FetchedVariables", function testA() {
       // We expect 2 Debugger:FetchedVariables events, one from the global object
       // scope and the regular one.
       if (++gCount < 2) {
         is(gCount, 1, "A. First Debugger:FetchedVariables event received.");
         return;
       }
       is(gCount, 2, "A. Second Debugger:FetchedVariables event received.");
@@ -43,17 +43,17 @@ function testWithFrame()
 
       is(gDebugger.DebuggerController.activeThread.state, "paused",
         "Should be paused now.");
 
       gDebugger.DebuggerView.Options._pauseOnExceptionsItem.setAttribute("checked", "true");
       gDebugger.DebuggerView.Options._togglePauseOnExceptions();
 
       gCount = 0;
-      gPane.contentWindow.gClient.addOneTimeListener("resumed", function() {
+      gPane.panelWin.gClient.addOneTimeListener("resumed", function() {
         gDebugger.addEventListener("Debugger:FetchedVariables", function testB() {
           // We expect 2 Debugger:FetchedVariables events, one from the global object
           // scope and the regular one.
           if (++gCount < 2) {
             is(gCount, 1, "B. First Debugger:FetchedVariables event received.");
             return;
           }
           is(gCount, 2, "B. Second Debugger:FetchedVariables event received.");
@@ -91,17 +91,17 @@ function testWithFrame()
   });
 
   EventUtils.sendMouseEvent({ type: "click" },
     content.document.querySelector("button"),
     content.window);
 }
 
 function resumeAndFinish() {
-  gPane.contentWindow.gClient.addOneTimeListener("resumed", function() {
+  gPane.panelWin.gClient.addOneTimeListener("resumed", function() {
     Services.tm.currentThread.dispatch({ run: function() {
 
       closeDebuggerAndFinish(false);
     }}, 0);
   });
 
   // Resume to let the exception reach it's catch clause.
   gDebugger.DebuggerController.activeThread.resume();
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -10,17 +10,17 @@ var gDebugger = null;
 var gView = null;
 var gLH = null;
 var gL10N = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gView = gDebugger.DebuggerView;
     gLH = gDebugger.LayoutHelpers;
     gL10N = gDebugger.L10N;
 
     testPause();
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_progress-listener-bug.js
+++ b/browser/devtools/debugger/test/browser_dbg_progress-listener-bug.js
@@ -13,17 +13,17 @@ var gOldListener = null;
 const TEST_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
 
 function test() {
   installListener();
 
   debug_tab_pane(TEST_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    let gDebugger = gPane.contentWindow;
+    let gDebugger = gPane.panelWin;
 
     is(gDebugger.DebuggerController._isInitialized, true,
       "Controller should be initialized after debug_tab_pane.");
     is(gDebugger.DebuggerView._isInitialized, true,
       "View should be initialized after debug_tab_pane.");
 
     closeDebuggerAndFinish();
   });
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-02.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-03.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-04.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-05.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-06.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-07.js
@@ -12,17 +12,17 @@ var gPane = null;
 var gTab = null;
 var gDebugger = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testFrameParameters();
   });
 }
 
 function testFrameParameters()
 {
   dump("Started testFrameParameters!\n");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js
@@ -12,17 +12,17 @@ var gPane = null;
 var gTab = null;
 var gDebugger = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testFrameParameters();
   });
 }
 
 function testFrameParameters()
 {
   dump("Started testFrameParameters!\n");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-09.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-09.js
@@ -14,17 +14,17 @@ var gDebugger = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.nonEnumVisible = false;
     testFrameParameters();
   });
 }
 
 function testFrameParameters()
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-10.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-10.js
@@ -14,17 +14,17 @@ var gDebugger = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.nonEnumVisible = false;
     testWithFrame();
   });
 }
 
 function testWithFrame()
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-data.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js
@@ -13,17 +13,17 @@ var gVariablesView = null;
 var gScope = null;
 var gVariable = null;
 
 function test()
 {
   debug_tab_pane(TAB1_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gVariablesView = gDebugger.DebuggerView.Variables;
 
     testVariablesView();
   });
 }
 
 function testVariablesView()
 {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-edit-watch.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-edit-watch.js
@@ -19,17 +19,17 @@ var gVars = null;
 
 requestLongerTimeout(2);
 
 function test() {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gWatch = gDebugger.DebuggerView.WatchExpressions;
     gVars = gDebugger.DebuggerView.Variables;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.nonEnumVisible = false;
     testFrameEval();
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-edit.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-edit.js
@@ -17,17 +17,17 @@ var gDebugger = null;
 
 requestLongerTimeout(2);
 
 function test() {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.nonEnumVisible = false;
     testFrameEval();
   });
 }
 
 function testFrameEval() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-01.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     testSearchbox();
     prepareVariables(testVariablesFiltering);
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-02.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     testSearchbox();
     prepareVariables(testVariablesFiltering);
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-03.js
@@ -19,17 +19,17 @@ function test()
   gPrevPref = Services.prefs.getBoolPref(
     "devtools.debugger.ui.variables-searchbox-visible");
   Services.prefs.setBoolPref(
     "devtools.debugger.ui.variables-searchbox-visible", false);
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     testSearchbox();
     testPref();
   });
 }
 
 function testSearchbox()
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-04.js
@@ -19,17 +19,17 @@ function test()
   gPrevPref = Services.prefs.getBoolPref(
     "devtools.debugger.ui.variables-searchbox-visible");
   Services.prefs.setBoolPref(
     "devtools.debugger.ui.variables-searchbox-visible", true);
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     testSearchbox();
     testPref();
   });
 }
 
 function testSearchbox()
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-05.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     prepareVariables(testVariablesFiltering);
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-06.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = false;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     prepareVariables(testVariablesFiltering);
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-07.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     prepareVariables(testVariablesFiltering);
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-filter-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-filter-08.js
@@ -16,17 +16,17 @@ var gSearchBox = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     gDebugger.DebuggerController.StackFrames.autoScopeExpand = true;
     gDebugger.DebuggerView.Variables.delayedSearch = false;
     prepareVariables(testVariablesFiltering);
   });
 }
 
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-reexpand.js
+++ b/browser/devtools/debugger/test/browser_dbg_propertyview-reexpand.js
@@ -15,17 +15,17 @@ var gDebuggee = null;
 
 requestLongerTimeout(2);
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebuggee = aDebuggee;
 
     addBreakpoint();
   });
 }
 
 function addBreakpoint()
 {
--- a/browser/devtools/debugger/test/browser_dbg_reload-preferred-script.js
+++ b/browser/devtools/debugger/test/browser_dbg_reload-preferred-script.js
@@ -22,17 +22,17 @@ function test()
   let scriptShownUrl = null;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gView = gDebugger.DebuggerView;
     resumed = true;
 
     gView.Sources.preferredSource = EXAMPLE_URL + expectedScript;
     startTest();
   });
 
   function onScriptShown(aEvent)
--- a/browser/devtools/debugger/test/browser_dbg_reload-same-script.js
+++ b/browser/devtools/debugger/test/browser_dbg_reload-same-script.js
@@ -23,17 +23,17 @@ function test()
   let scriptShownUrl = null;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gView = gDebugger.DebuggerView;
     resumed = true;
 
     startTest();
   });
 
   function onScriptShown(aEvent)
   {
--- a/browser/devtools/debugger/test/browser_dbg_script-switching.js
+++ b/browser/devtools/debugger/test/browser_dbg_script-switching.js
@@ -20,17 +20,17 @@ function test()
   let framesAdded = false;
   let resumed = false;
   let testStarted = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
     executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js
@@ -19,17 +19,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.simpleCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js
@@ -21,17 +21,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-03.js
@@ -22,17 +22,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-04.js
@@ -22,17 +22,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-05.js
@@ -22,17 +22,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-06.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-06.js
@@ -22,17 +22,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-07.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-07.js
@@ -23,17 +23,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-08.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-08.js
@@ -22,17 +22,17 @@ function test()
 {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gDebugger.SourceResults.prototype.alwaysExpand = false;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-popup.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-popup.js
@@ -13,17 +13,17 @@ var gSearchBox = null;
 var gSearchBoxPanel = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       runTest();
     });
 
     gDebuggee.firstCall();
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js
+++ b/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js
@@ -8,17 +8,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_select-line.js
+++ b/browser/devtools/debugger/test/browser_dbg_select-line.js
@@ -19,17 +19,17 @@ var gDebugger = null;
 var gScripts = null;
 
 function test()
 {
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSelectLine();
   });
 }
 
 function testSelectLine() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("scriptsadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-01.js
+++ b/browser/devtools/debugger/test/browser_dbg_stack-01.js
@@ -9,17 +9,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testSimpleCall();
   });
 }
 
 function testSimpleCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-02.js
+++ b/browser/devtools/debugger/test/browser_dbg_stack-02.js
@@ -9,17 +9,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testEvalCall();
   });
 }
 
 function testEvalCall() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-03.js
+++ b/browser/devtools/debugger/test/browser_dbg_stack-03.js
@@ -9,17 +9,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testRecurse();
   });
 }
 
 function testRecurse() {
   gDebuggee.gRecurseLimit = (gDebugger.gCallStackPageSize * 2) + 1;
 
--- a/browser/devtools/debugger/test/browser_dbg_stack-04.js
+++ b/browser/devtools/debugger/test/browser_dbg_stack-04.js
@@ -9,17 +9,17 @@ var gTab = null;
 var gDebuggee = null;
 var gDebugger = null;
 
 function test() {
   debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     testEvalCallResume();
   });
 }
 
 function testEvalCallResume() {
   gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
     Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-05.js
+++ b/browser/devtools/debugger/test/browser_dbg_stack-05.js
@@ -17,17 +17,17 @@ var gDebugger = null;
 function test() {
   let scriptShown = false;
   let framesAdded = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       runTest();
     });
 
     gDebuggee.firstCall();
   });
--- a/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js
+++ b/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js
@@ -24,17 +24,17 @@ function test()
   let framesAdded = false;
   let testStarted = false;
   let resumed = false;
 
   debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
     gTab = aTab;
     gDebuggee = aDebuggee;
     gPane = aPane;
-    gDebugger = gPane.contentWindow;
+    gDebugger = gPane.panelWin;
     gScripts = gDebugger.DebuggerView.Sources._container;
     resumed = true;
 
     gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
       framesAdded = true;
       executeSoon(startTest);
     });
 
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -9,16 +9,20 @@ const Cu = Components.utils;
 let tempScope = {};
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope);
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm", tempScope);
 Cu.import("resource://gre/modules/Services.jsm", tempScope);
 let DebuggerServer = tempScope.DebuggerServer;
 let DebuggerTransport = tempScope.DebuggerTransport;
 let DebuggerClient = tempScope.DebuggerClient;
 let Services = tempScope.Services;
+Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
+let gDevTools = tempScope.gDevTools;
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/";
 const TAB1_URL = EXAMPLE_URL + "browser_dbg_tab1.html";
 const TAB2_URL = EXAMPLE_URL + "browser_dbg_tab2.html";
 const STACK_URL = EXAMPLE_URL + "browser_dbg_stack.html";
 
 // Enable logging and remote debugging for the relevant tests.
 let gEnableRemote = Services.prefs.getBoolPref("devtools.debugger.remote-enabled");
@@ -81,123 +85,131 @@ function addTab(aURL, aOnload, aWindow) 
 function removeTab(aTab, aWindow) {
   let targetWindow = aWindow || window;
   let targetBrowser = targetWindow.gBrowser;
 
   targetBrowser.removeTab(aTab);
 }
 
 function closeDebuggerAndFinish(aRemoteFlag, aCallback, aWindow) {
-  let targetWindow = aWindow || window;
-  let debuggerUI = targetWindow.DebuggerUI;
-
   let debuggerClosed = false;
   let debuggerDisconnected = false;
+  // let targetWindow = aWindow || window;
+  ok(gTab, "There is a gTab to use for getting a toolbox reference");
+  let target = TargetFactory.forTab(gTab);
+
+  // let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+  window.addEventListener("Debugger:Shutdown", function cleanup() {
+    window.removeEventListener("Debugger:Shutdown", cleanup, false);
+    debuggerDisconnected = true;
+    _maybeFinish();
+  }, false);
+
+  let toolbox = gDevTools.getToolboxForTarget(target);
+  toolbox.once("destroyed", function() {
+    debuggerClosed = true;
+    _maybeFinish();
+  });
+  toolbox.destroy();
 
   function _maybeFinish() {
     if (debuggerClosed && debuggerDisconnected) {
       if (!aCallback)
         aCallback = finish;
       aCallback();
     }
   }
 
-  debuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
-    debuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
-    debuggerDisconnected = true;
-    _maybeFinish();
-  }, false);
-  if (!aRemoteFlag) {
-    debuggerUI.getDebugger().close(function() {
-      debuggerClosed = true;
-      _maybeFinish();
-    });
-  } else {
-    debuggerClosed = true;
-    debuggerUI.getRemoteDebugger().close();
-  }
+  // if (!aRemoteFlag) {
+  //   dbg.getDebugger().close(function() {
+  //     debuggerClosed = true;
+  //     _maybeFinish();
+  //   });
+  // } else {
+  //   debuggerClosed = true;
+  //   dbg.getRemoteDebugger().close();
+  // }
 }
 
 function get_tab_actor_for_url(aClient, aURL, aCallback) {
   aClient.listTabs(function(aResponse) {
     for each (let tab in aResponse.tabs) {
       if (tab.url == aURL) {
         aCallback(tab);
         return;
       }
     }
   });
 }
 
 function attach_tab_actor_for_url(aClient, aURL, aCallback) {
   get_tab_actor_for_url(aClient, aURL, function(actor) {
-    aClient.request({ to: actor.actor, type: "attach" }, function(aResponse) {
+    aClient.attachTab(actor.actor, function(aResponse) {
       aCallback(actor, aResponse);
     });
   });
 }
 
 function attach_thread_actor_for_url(aClient, aURL, aCallback) {
   attach_tab_actor_for_url(aClient, aURL, function(aTabActor, aResponse) {
-    aClient.request({ "to": actor.threadActor, "type": "attach" }, function(aResponse) {
+    aClient.attachThread(actor.threadActor, function(aResponse, aThreadClient) {
       // We don't care about the pause right now (use
       // get_actor_for_url() if you do), so resume it.
-      aClient.request({ to: actor.threadActor, type: "resume" }, function(aResponse) {
+      aThreadClient.resume(function(aResponse) {
         aCallback(actor);
       });
     });
   });
 }
 
-function wait_for_connect_and_resume(aOnDebugging, aWindow) {
-  let targetWindow = aWindow || window;
-  let targetDocument = targetWindow.document;
-
-  targetDocument.addEventListener("Debugger:Connected", function dbgConnected(aEvent) {
-    targetDocument.removeEventListener("Debugger:Connected", dbgConnected, true);
-
+function wait_for_connect_and_resume(aOnDebugging, aTab) {
+  let target = TargetFactory.forTab(aTab);
+  let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+  dbg.once("connected", function dbgConnected() {
     // Wait for the initial resume...
-    aEvent.target.ownerDocument.defaultView.gClient.addOneTimeListener("resumed", function() {
+    dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
       aOnDebugging();
     });
-  }, true);
+  });
 }
 
 function debug_tab_pane(aURL, aOnDebugging) {
   let tab = addTab(aURL, function() {
     gBrowser.selectedTab = gTab;
-    let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
-
-    let pane = DebuggerUI.toggleDebugger();
-    pane._frame.addEventListener("Debugger:Connected", function dbgConnected() {
-      pane._frame.removeEventListener("Debugger:Connected", dbgConnected, true);
+    let debuggee = gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
 
-      // Wait for the initial resume...
-      pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
-        pane.contentWindow.DebuggerView.Variables.lazyEmpty = false;
-        aOnDebugging(tab, debuggee, pane);
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let toolbox = gDevTools.openToolboxForTab(target, "jsdebugger");
+    toolbox.once("jsdebugger-ready", function dbgReady() {
+      let dbg = gDevTools.getPanelForTarget("jsdebugger", target);
+      dbg.once("connected", function() {
+        // Wait for the initial resume...
+        dbg.panelWin.gClient.addOneTimeListener("resumed", function() {
+          dbg._view.Variables.lazyEmpty = false;
+          aOnDebugging(tab, debuggee, dbg);
+        });
       });
-    }, true);
+    });
   });
 }
 
 function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) {
   // Make any necessary preparations (start the debugger server etc.)
   aBeforeTabAdded();
 
   let tab = addTab(aURL, function() {
     gBrowser.selectedTab = gTab;
     let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
 
     let win = DebuggerUI.toggleRemoteDebugger();
     win._dbgwin.addEventListener("Debugger:Connected", function dbgConnected() {
       win._dbgwin.removeEventListener("Debugger:Connected", dbgConnected, true);
 
       // Wait for the initial resume...
-      win.contentWindow.gClient.addOneTimeListener("resumed", function() {
+      win.panelWin.gClient.addOneTimeListener("resumed", function() {
         win._dbgwin.DebuggerView.Variables.lazyEmpty = false;
         aOnDebugging(tab, debuggee, win);
       });
     }, true);
   });
 }
 
 function debug_chrome(aURL, aOnClosing, aOnDebugging) {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/Makefile.in
@@ -0,0 +1,18 @@
+#
+# 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/.
+
+DEPTH		= @DEPTH@
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+TEST_DIRS += test
+
+include $(topsrcdir)/config/rules.mk
+
+libs::
+	$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/Sidebar.jsm
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const Cc = Components.classes;
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+this.EXPORTED_SYMBOLS = ["ToolSidebar"];
+
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+
+const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+/**
+ * ToolSidebar provides methods to register tabs in the sidebar.
+ * It's assumed that the sidebar contains a xul:tabbox.
+ *
+ * @param {Node} tabbox
+ *  <tabbox> node;
+ * @param {ToolPanel} panel
+ *  Related ToolPanel instance;
+ * @param {Boolean} showTabstripe
+ *  Show the tabs.
+ */
+this.ToolSidebar = function ToolSidebar(tabbox, panel, showTabstripe=true)
+{
+  new EventEmitter(this);
+
+  this._tabbox = tabbox;
+  this._panelDoc = this._tabbox.ownerDocument;
+  this._toolPanel = panel;
+
+  this._tabbox.tabpanels.addEventListener("select", this, true);
+
+  this._tabs = new Map();
+
+  if (!showTabstripe) {
+    this._tabbox.setAttribute("hidetabs", "true");
+  }
+}
+
+ToolSidebar.prototype = {
+  /**
+   * Register a tab. A tab is a document.
+   * The document must have a title, which will be used as the name of the tab.
+   *
+   * @param {string} tab uniq id
+   * @param {string} url
+   */
+  addTab: function ToolSidebar_addTab(id, url, selected=false) {
+    let iframe = this._panelDoc.createElementNS(XULNS, "iframe");
+    iframe.className = "iframe-" + id;
+    iframe.setAttribute("flex", "1");
+    iframe.setAttribute("src", url);
+
+    let tab = this._tabbox.tabs.appendItem();
+
+    let onIFrameLoaded = function() {
+      tab.setAttribute("label", iframe.contentDocument.title);
+      iframe.removeEventListener("DOMContentLoaded", onIFrameLoaded, true);
+      if ("setPanel" in iframe.contentWindow) {
+        iframe.contentWindow.setPanel(this._toolPanel, iframe);
+      }
+      this.emit(id + "-ready");
+    }.bind(this);
+
+    iframe.addEventListener("DOMContentLoaded", onIFrameLoaded, true);
+
+    let tabpanel = this._panelDoc.createElementNS(XULNS, "tabpanel");
+    tabpanel.setAttribute("id", "sidebar-panel-" + id);
+    tabpanel.appendChild(iframe);
+    this._tabbox.tabpanels.appendChild(tabpanel);
+
+    tab.linkedPanel = "sidebar-panel-" + id;
+
+    // We store the index of this tab.
+    this._tabs.set(id, tab);
+
+    if (selected) {
+      // For some reason I don't understand, if we call this.select in this
+      // event loop (after inserting the tab), the tab will never get the
+      // the "selected" attribute set to true.
+      this._panelDoc.defaultView.setTimeout(function() {
+        this.select(id);
+      }.bind(this), 0);
+    }
+
+    this.emit("new-tab-registered", id);
+  },
+
+  /**
+   * Select a specific tab.
+   */
+  select: function ToolSidebar_select(id) {
+    let tab = this._tabs.get(id);
+    if (tab) {
+      this._tabbox.selectedTab = tab;
+    }
+  },
+
+  /**
+   * Return the id of the selected tab.
+   */
+  getCurrentTabID: function ToolSidebar_getCurrentTabID() {
+    let currentID = null;
+    for (let [id, tab] of this._tabs) {
+      if (this._tabbox.tabs.selectedItem == tab) {
+        currentID = id;
+        break;
+      }
+    }
+    return currentID;
+  },
+
+  /**
+   * Event handler.
+   */
+  handleEvent: function ToolSidebar_eventHandler(event) {
+    if (event.type == "select") {
+      let previousTool = this._currentTool;
+      this._currentTool = this.getCurrentTabID();
+      if (previousTool) {
+        this.emit(previousTool + "-unselected");
+      }
+
+      this.emit(this._currentTool + "-selected");
+      this.emit("select", this._currentTool);
+    }
+  },
+
+
+  /**
+   * Toggle sidebar's visibility state.
+   */
+  toggle: function ToolSidebar_toggle() {
+    if (this._tabbox.hasAttribute("hidden")) {
+      this.show();
+    } else {
+      this.hide();
+    }
+  },
+
+  /**
+   * Show the sidebar.
+   */
+  show: function ToolSidebar_show() {
+    this._tabbox.removeAttribute("hidden");
+  },
+
+  /**
+   * Show the sidebar.
+   */
+  hide: function ToolSidebar_hide() {
+    this._tabbox.setAttribute("hidden", "true");
+  },
+
+  /**
+   * Return the window containing the tab content.
+   */
+  getWindowForTab: function ToolSidebar_getWindowForTab(id) {
+    if (!this._tabs.has(id)) {
+      return null;
+    }
+
+    let panel = this._panelDoc.getElementById(this._tabs.get(id).linkedPanel);
+    return panel.firstChild.contentWindow;
+  },
+
+  /**
+   * Clean-up.
+   */
+  destroy: function ToolSidebar_destroy() {
+    this._tabbox.removeEventListener("select", this, true);
+
+    while (this._tabbox.tabpanels.hasChildNodes()) {
+      this._tabbox.tabpanels.removeChild(this._tabbox.tabpanels.firstChild);
+    }
+
+    while (this._tabbox.tabs.hasChildNodes()) {
+      this._tabbox.tabs.removeChild(this._tabbox.tabs.firstChild);
+    }
+
+    this._tabs = null;
+    this._tabbox = null;
+    this._panelDoc = null;
+    this._toolPanel = null;
+  },
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/Target.jsm
@@ -0,0 +1,385 @@
+/* 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.EXPORTED_SYMBOLS = [ "TargetFactory" ];
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+
+const targets = new WeakMap();
+
+/**
+ * Functions for creating Targets
+ */
+this.TargetFactory = {
+  /**
+   * Construct a Target
+   * @param {XULTab} tab
+   *        The tab to use in creating a new target
+   * @return A target object
+   */
+  forTab: function TF_forTab(tab) {
+    let target = targets.get(tab);
+    if (target == null) {
+      target = new TabTarget(tab);
+      targets.set(tab, target);
+    }
+    return target;
+  },
+
+  /**
+   * Creating a target for a tab that is being closed is a problem because it
+   * allows a leak as a result of coming after the close event which normally
+   * clears things up. This function allows us to ask if there is a known
+   * target for a tab without creating a target
+   * @return true/false
+   */
+  isKnownTab: function TF_isKnownTab(tab) {
+    return targets.has(tab);
+  },
+
+  /**
+   * Construct a Target
+   * @param {nsIDOMWindow} window
+   *        The chromeWindow to use in creating a new target
+   * @return A target object
+   */
+  forWindow: function TF_forWindow(window) {
+    let target = targets.get(window);
+    if (target == null) {
+      target = new WindowTarget(window);
+      targets.set(window, target);
+    }
+    return target;
+  },
+
+  /**
+   * Construct a Target for a remote global
+   * @param {Object} form
+   *        The serialized form of a debugging protocol actor.
+   * @param {DebuggerClient} client
+   *        The debuger client instance to communicate with the server.
+   * @param {boolean} chrome
+   *        A flag denoting that the debugging target is the remote process as a
+   *        whole and not a single tab.
+   * @return A target object
+   */
+  forRemote: function TF_forRemote(form, client, chrome) {
+    let target = targets.get(form);
+    if (target == null) {
+      target = new RemoteTarget(form, client, chrome);
+      targets.set(form, target);
+    }
+    return target;
+  },
+
+  /**
+   * Get all of the targets known to some browser instance (local if null)
+   * @return An array of target objects
+   */
+  allTargets: function TF_allTargets() {
+    let windows = [];
+    let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                       .getService(Components.interfaces.nsIWindowMediator);
+    let en = wm.getXULWindowEnumerator(null);
+    while (en.hasMoreElements()) {
+      windows.push(en.getNext());
+    }
+
+    return windows.map(function(window) {
+      return TargetFactory.forWindow(window);
+    });
+  },
+};
+
+/**
+ * The 'version' property allows the developer tools equivalent of browser
+ * detection. Browser detection is evil, however while we don't know what we
+ * will need to detect in the future, it is an easy way to postpone work.
+ * We should be looking to use 'supports()' in place of version where
+ * possible.
+ */
+function getVersion() {
+  // FIXME: return something better
+  return 20;
+}
+
+/**
+ * A better way to support feature detection, but we're not yet at a place
+ * where we have the features well enough defined for this to make lots of
+ * sense.
+ */
+function supports(feature) {
+  // FIXME: return something better
+  return false;
+};
+
+/**
+ * A Target represents something that we can debug. Targets are generally
+ * read-only. Any changes that you wish to make to a target should be done via
+ * a Tool that attaches to the target. i.e. a Target is just a pointer saying
+ * "the thing to debug is over there".
+ *
+ * Providing a generalized abstraction of a web-page or web-browser (available
+ * either locally or remotely) is beyond the scope of this class (and maybe
+ * also beyond the scope of this universe) However Target does attempt to
+ * abstract some common events and read-only properties common to many Tools.
+ *
+ * Supported read-only properties:
+ * - name, isRemote, url
+ *
+ * Target extends EventEmitter and provides support for the following events:
+ * - close: The target window has been closed. All tools attached to this
+ *     target should close. This event is not currently cancelable.
+ * - navigate: The target window has navigated to a different URL
+ *
+ * Optional events:
+ * - will-navigate: The target window will navigate to a different URL
+ * - hidden: The target is not visible anymore (for TargetTab, another tab is selected)
+ * - visible: The target is visible (for TargetTab, tab is selected)
+ *
+ * Target also supports 2 functions to help allow 2 different versions of
+ * Firefox debug each other. The 'version' property is the equivalent of
+ * browser detection - simple and easy to implement but gets fragile when things
+ * are not quite what they seem. The 'supports' property is the equivalent of
+ * feature detection - harder to setup, but more robust long-term.
+ *
+ * Comparing Targets: 2 instances of a Target object can point at the same
+ * thing, so t1 !== t2 and t1 != t2 even when they represent the same object.
+ * To compare to targets use 't1.equals(t2)'.
+ */
+function Target() {
+  throw new Error("Use TargetFactory.newXXX or Target.getXXX to create a Target in place of 'new Target()'");
+}
+
+Object.defineProperty(Target.prototype, "version", {
+  get: getVersion,
+  enumerable: true
+});
+
+
+/**
+ * A TabTarget represents a page living in a browser tab. Generally these will
+ * be web pages served over http(s), but they don't have to be.
+ */
+function TabTarget(tab) {
+  new EventEmitter(this);
+  this._tab = tab;
+  this._setupListeners();
+}
+
+TabTarget.prototype = {
+  _webProgressListener: null,
+
+  supports: supports,
+  get version() { return getVersion(); },
+
+  get tab() {
+    return this._tab;
+  },
+
+  get name() {
+    return this._tab.linkedBrowser.contentDocument.title;
+  },
+
+  get url() {
+    return this._tab.linkedBrowser.contentDocument.location.href;
+  },
+
+  get isRemote() {
+    return false;
+  },
+
+  /**
+   * Listen to the different tabs events.
+   */
+  _setupListeners: function TabTarget__setupListeners() {
+    this._webProgressListener = new TabWebProgressListener(this);
+    this.tab.linkedBrowser.addProgressListener(this._webProgressListener);
+    this.tab.addEventListener("TabClose", this);
+    this.tab.parentNode.addEventListener("TabSelect", this);
+  },
+
+  /**
+   * Handle tabs events.
+   */
+  handleEvent: function (event) {
+    switch (event.type) {
+      case "TabClose":
+        this.destroy();
+        break;
+      case "TabSelect":
+        if (this.tab.selected) {
+          this.emit("visible", event);
+        } else {
+          this.emit("hidden", event);
+        }
+        break;
+    }
+  },
+
+
+  /**
+   * Target is not alive anymore.
+   */
+  destroy: function() {
+    if (this._destroyed) {
+      return;
+    }
+    this.tab.linkedBrowser.removeProgressListener(this._webProgressListener)
+    this._webProgressListener.target = null;
+    this._webProgressListener = null;
+    this.tab.removeEventListener("TabClose", this);
+    this.tab.parentNode.removeEventListener("TabSelect", this);
+    this._destroyed = true;
+    this.emit("close");
+
+    targets.delete(this._tab);
+    this._tab = null;
+  },
+
+  toString: function() {
+    return 'TabTarget:' + this.tab;
+  },
+};
+
+
+/**
+ * WebProgressListener for TabTarget.
+ *
+ * @param object aTarget
+ *        The TabTarget instance to work with.
+ */
+function TabWebProgressListener(aTarget) {
+  this.target = aTarget;
+}
+
+TabWebProgressListener.prototype = {
+  target: null,
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
+
+  onStateChange: function TWPL_onStateChange(progress, request, flag, status) {
+    let isStart = flag & Ci.nsIWebProgressListener.STATE_START;
+    let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
+    let isNetwork = flag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+    let isRequest = flag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
+
+    // Skip non-interesting states.
+    if (!isStart || !isDocument || !isRequest || !isNetwork) {
+      return;
+    }
+
+    if (this.target) {
+      this.target.emit("will-navigate", request);
+    }
+  },
+
+  onProgressChange: function() {},
+  onSecurityChange: function() {},
+  onStatusChange: function() {},
+
+  onLocationChange: function TwPL_onLocationChange(webProgress) {
+    let window = webProgress.DOMWindow;
+    if (this.target) {
+      this.target.emit("navigate", window);
+    }
+  },
+};
+
+
+/**
+ * A WindowTarget represents a page living in a xul window or panel. Generally
+ * these will have a chrome: URL
+ */
+function WindowTarget(window) {
+  new EventEmitter(this);
+  this._window = window;
+}
+
+WindowTarget.prototype = {
+  supports: supports,
+  get version() { return getVersion(); },
+
+  get window() {
+    return this._window;
+  },
+
+  get name() {
+    return this._window.document.title;
+  },
+
+  get url() {
+    return this._window.document.location.href;
+  },
+
+  get isRemote() {
+    return false;
+  },
+
+  toString: function() {
+    return 'WindowTarget:' + this.window;
+  },
+};
+
+/**
+ * A RemoteTarget represents a page living in a remote Firefox instance.
+ */
+function RemoteTarget(form, client, chrome) {
+  new EventEmitter(this);
+  this._client = client;
+  this._form = form;
+  this._chrome = chrome;
+
+  this.destroy = this.destroy.bind(this);
+  this.client.addListener("tabDetached", this.destroy);
+
+  this._onTabNavigated = function onRemoteTabNavigated() {
+    this.emit("navigate");
+  }.bind(this);
+  this.client.addListener("tabNavigated", this._onTabNavigated);
+}
+
+RemoteTarget.prototype = {
+  supports: supports,
+  get version() getVersion(),
+
+  get isRemote() true,
+
+  get chrome() this._chrome,
+
+  get name() this._form._title,
+
+  get url() this._form._url,
+
+  get client() this._client,
+
+  get form() this._form,
+
+  /**
+   * Target is not alive anymore.
+   */
+  destroy: function RT_destroy() {
+    if (this._destroyed) {
+      return;
+    }
+    this.client.removeListener("tabNavigated", this._onTabNavigated);
+    this.client.removeListener("tabDetached", this.destroy);
+
+    this._client.close(function onClosed() {
+      this._client = null;
+      this._destroyed = true;
+      this.emit("close");
+    }.bind(this));
+  },
+
+  toString: function() {
+    return 'RemoteTarget:' + this.form.actor;
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/ToolDefinitions.jsm
@@ -0,0 +1,154 @@
+/* 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.EXPORTED_SYMBOLS = [
+                          "defaultTools",
+                          "webConsoleDefinition",
+                          "debuggerDefinition",
+                          "inspectorDefinition",
+                          "styleEditorDefinition"
+                        ];
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+const inspectorProps = "chrome://browser/locale/devtools/inspector.properties";
+const debuggerProps = "chrome://browser/locale/devtools/debugger.properties";
+const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.properties";
+const webConsoleProps = "chrome://browser/locale/devtools/webconsole.properties";
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "osString",
+  function() Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS);
+
+// Panels
+XPCOMUtils.defineLazyModuleGetter(this, "WebConsolePanel",
+  "resource:///modules/WebConsolePanel.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "DebuggerPanel",
+  "resource:///modules/devtools/DebuggerPanel.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "StyleEditorPanel",
+  "resource:///modules/devtools/StyleEditorPanel.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "InspectorPanel",
+  "resource:///modules/devtools/InspectorPanel.jsm");
+
+// Strings
+XPCOMUtils.defineLazyGetter(this, "webConsoleStrings",
+  function() Services.strings.createBundle(webConsoleProps));
+
+XPCOMUtils.defineLazyGetter(this, "debuggerStrings",
+  function() Services.strings.createBundle(debuggerProps));
+
+XPCOMUtils.defineLazyGetter(this, "styleEditorStrings",
+  function() Services.strings.createBundle(styleEditorProps));
+
+XPCOMUtils.defineLazyGetter(this, "inspectorStrings",
+  function() Services.strings.createBundle(inspectorProps));
+
+// Definitions
+let webConsoleDefinition = {
+  id: "webconsole",
+  key: l10n("cmd.commandkey", webConsoleStrings),
+  accesskey: l10n("webConsoleCmd.accesskey", webConsoleStrings),
+  modifiers: Services.appinfo.OS == "Darwin" ? "accel,alt" : "accel,shift",
+  ordinal: 0,
+  icon: "chrome://browser/skin/devtools/webconsole-tool-icon.png",
+  url: "chrome://browser/content/devtools/webconsole.xul",
+  label: l10n("ToolboxWebconsole.label", webConsoleStrings),
+  isTargetSupported: function(target) {
+    return true;
+  },
+  build: function(iframeWindow, toolbox) {
+    return new WebConsolePanel(iframeWindow, toolbox);
+  }
+};
+
+let debuggerDefinition = {
+  id: "jsdebugger",
+  key: l10n("open.commandkey", debuggerStrings),
+  accesskey: l10n("debuggerMenu.accesskey", debuggerStrings),
+  modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
+  ordinal: 1,
+  killswitch: "devtools.debugger.enabled",
+  icon: "chrome://browser/skin/devtools/tools-icons-small.png",
+  url: "chrome://browser/content/debugger.xul",
+  label: l10n("ToolboxDebugger.label", debuggerStrings),
+
+  isTargetSupported: function(target) {
+    return true;
+  },
+
+  build: function(iframeWindow, toolbox) {
+    return new DebuggerPanel(iframeWindow, toolbox);
+  }
+};
+
+let inspectorDefinition = {
+  id: "inspector",
+  accesskey: l10n("inspector.accesskey", inspectorStrings),
+  key: l10n("inspector.commandkey", inspectorStrings),
+  ordinal: 2,
+  modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
+  icon: "chrome://browser/skin/devtools/tools-icons-small.png",
+  url: "chrome://browser/content/devtools/inspector/inspector.xul",
+  label: l10n("inspector.label", inspectorStrings),
+
+  isTargetSupported: function(target) {
+    return !target.isRemote;
+  },
+
+  build: function(iframeWindow, toolbox) {
+    return new InspectorPanel(iframeWindow, toolbox);
+  }
+};
+
+let styleEditorDefinition = {
+  id: "styleeditor",
+  key: l10n("open.commandkey", styleEditorStrings),
+  ordinal: 3,
+  accesskey: l10n("open.accesskey", styleEditorStrings),
+  modifiers: "shift",
+  label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
+  url: "chrome://browser/content/styleeditor.xul",
+
+  isTargetSupported: function(target) {
+    return !target.isRemote && !target.isChrome;
+  },
+
+  build: function(iframeWindow, toolbox) {
+    return new StyleEditorPanel(iframeWindow, toolbox);
+  }
+};
+
+this.defaultTools = [
+  styleEditorDefinition,
+  webConsoleDefinition,
+  debuggerDefinition,
+  inspectorDefinition,
+];
+
+/**
+ * Lookup l10n string from a string bundle.
+ *
+ * @param {string} name
+ *        The key to lookup.
+ * @param {StringBundle} bundle
+ *        The key to lookup.
+ * @returns A localized version of the given key.
+ */
+function l10n(name, bundle)
+{
+  try {
+    return bundle.GetStringFromName(name);
+  } catch (ex) {
+    Services.console.logStringMessage("Error reading '" + name + "'");
+    throw new Error("l10n error with " + name);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -0,0 +1,525 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+Cu.import("resource:///modules/devtools/gDevTools.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Hosts",
+                                  "resource:///modules/devtools/ToolboxHosts.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
+                                  "resource:///modules/devtools/DeveloperToolbar.jsm");
+
+// DO NOT put Require.jsm or gcli.jsm into lazy getters as this breaks the
+// requisition import a few lines down.
+Cu.import("resource://gre/modules/devtools/gcli.jsm");
+Cu.import("resource://gre/modules/devtools/Require.jsm");
+
+let Requisition = require('gcli/cli').Requisition;
+let CommandOutputManager = require('gcli/canon').CommandOutputManager;
+
+this.EXPORTED_SYMBOLS = [ "Toolbox" ];
+
+/**
+ * A "Toolbox" is the component that holds all the tools for one specific
+ * target. Visually, it's a document that includes the tools tabs and all
+ * the iframes where the tool panels will be living in.
+ *
+ * @param {object} target
+ *        The object the toolbox is debugging.
+ * @param {Toolbox.HostType} hostType
+ *        Type of host that will host the toolbox (e.g. sidebar, window)
+ * @param {string} selectedTool
+ *        Tool to select initially
+ */
+this.Toolbox = function Toolbox(target, hostType, selectedTool) {
+  this._target = target;
+  this._toolPanels = new Map();
+
+  this._onLoad = this._onLoad.bind(this);
+  this._toolRegistered = this._toolRegistered.bind(this);
+  this._toolUnregistered = this._toolUnregistered.bind(this);
+  this.destroy = this.destroy.bind(this);
+
+  this._target.once("close", this.destroy);
+
+  if (!hostType) {
+    hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
+  }
+  if (!selectedTool) {
+    selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
+  }
+  let definitions = gDevTools.getToolDefinitions();
+  if (!definitions.get(selectedTool)) {
+    selectedTool = "webconsole";
+  }
+  this._defaultToolId = selectedTool;
+
+  this._host = this._createHost(hostType);
+
+  new EventEmitter(this);
+
+  gDevTools.on("tool-registered", this._toolRegistered);
+  gDevTools.on("tool-unregistered", this._toolUnregistered);
+}
+
+/**
+ * The toolbox can be 'hosted' either embedded in a browser window
+ * or in a separate window.
+ */
+Toolbox.HostType = {
+  BOTTOM: "bottom",
+  SIDE: "side",
+  WINDOW: "window"
+}
+
+Toolbox.prototype = {
+  _URL: "chrome://browser/content/devtools/framework/toolbox.xul",
+
+  _prefs: {
+    LAST_HOST: "devtools.toolbox.host",
+    LAST_TOOL: "devtools.toolbox.selectedTool",
+    SIDE_ENABLED: "devtools.toolbox.sideEnabled"
+  },
+
+  HostType: Toolbox.HostType,
+
+  /**
+   * Returns a *copy* of the _toolPanels collection.
+   *
+   * @return {Map} panels
+   *         All the running panels in the toolbox
+   */
+  getToolPanels: function TB_getToolPanels() {
+    let panels = new Map();
+
+    for (let [key, value] of this._toolPanels) {
+      panels.set(key, value);
+    }
+    return panels;
+  },
+
+  /**
+   * Get/alter the target of a Toolbox so we're debugging something different.
+   * See Target.jsm for more details.
+   * TODO: Do we allow |toolbox.target = null;| ?
+   */
+  get target() {
+    return this._target;
+  },
+
+  set target(value) {
+    this._target = value;
+  },
+
+  /**
+   * Get/alter the host of a Toolbox, i.e. is it in browser or in a separate
+   * tab. See HostType for more details.
+   */
+  get hostType() {
+    return this._host.type;
+  },
+
+  set hostType(value) {
+    this._switchToHost(value);
+  },
+
+  /**
+   * Get/alter the currently displayed tool.
+   */
+  get currentToolId() {
+    return this._currentToolId;
+  },
+
+  set currentToolId(value) {
+    this._currentToolId = value;
+  },
+
+  /**
+   * Get the iframe containing the toolbox UI.
+   */
+  get frame() {
+    return this._host.frame;
+  },
+
+  /**
+   * Shortcut to the document containing the toolbox UI
+   */
+  get doc() {
+    return this.frame.contentDocument;
+  },
+
+  /**
+   * Open the toolbox
+   */
+  open: function TBOX_open() {
+    this._host.once("ready", function(event, iframe) {
+      iframe.addEventListener("DOMContentLoaded", this._onLoad, true);
+      iframe.setAttribute("src", this._URL);
+    }.bind(this));
+
+    this._host.open();
+  },
+
+  /**
+   * Build the buttons for changing hosts. Called every time
+   * the host changes.
+   */
+  _buildDockButtons: function TBOX_createDockButtons() {
+    let dockBox = this.doc.getElementById("toolbox-dock-buttons");
+
+    while (dockBox.firstChild) {
+      dockBox.removeChild(dockBox.firstChild);
+    }
+
+    let sideEnabled = Services.prefs.getBoolPref(this._prefs.SIDE_ENABLED);
+
+    for each (let position in this.HostType) {
+      if (position == this.hostType ||
+         (!sideEnabled && position == this.HostType.SIDE)) {
+        continue;
+      }
+
+      let button = this.doc.createElement("toolbarbutton");
+      button.id = "toolbox-dock-" + position;
+      button.className = "toolbox-dock-button";
+      button.addEventListener("command", function(position) {
+        this.hostType = position;
+      }.bind(this, position));
+
+      dockBox.appendChild(button);
+    }
+  },
+
+  /**
+   * Onload handler for the toolbox's iframe
+   */
+  _onLoad: function TBOX_onLoad() {
+    this.frame.removeEventListener("DOMContentLoaded", this._onLoad, true);
+    this.isReady = true;
+
+    let closeButton = this.doc.getElementById("toolbox-close");
+    closeButton.addEventListener("command", this.destroy, true);
+
+    this._buildDockButtons();
+
+    this._buildTabs();
+    this._buildButtons(this.frame);
+
+    this.selectTool(this._defaultToolId);
+
+    this.emit("ready");
+  },
+
+  /**
+   * Add tabs to the toolbox UI for registered tools
+   */
+  _buildTabs: function TBOX_buildTabs() {
+    for (let [id, definition] of gDevTools.getToolDefinitions()) {
+      this._buildTabForTool(definition);
+    }
+  },
+
+  /**
+   * Add buttons to the UI as specified in the devtools.window.toolbarSpec pref
+   *
+   * @param {iframe} frame
+   *        The iframe to contain the buttons
+   */
+  _buildButtons: function TBOX_buildButtons(frame) {
+    let toolbarSpec = CommandUtils.getCommandbarSpec("devtools.toolbox.toolbarSpec");
+    let environment = { chromeDocument: frame.ownerDocument };
+    let requisition = new Requisition(environment);
+    requisition.commandOutputManager = new CommandOutputManager();
+
+    let buttons = CommandUtils.createButtons(toolbarSpec, this.doc, requisition);
+
+    let container = this.doc.getElementById("toolbox-buttons");
+    buttons.forEach(function(button) {
+      container.appendChild(button);
+    }.bind(this));
+  },
+
+  /**
+   * Build a tab for one tool definition and add to the toolbox
+   *
+   * @param {string} toolDefinition
+   *        Tool definition of the tool to build a tab for.
+   */
+  _buildTabForTool: function TBOX_buildTabForTool(toolDefinition) {
+    const MAX_ORDINAL = 99;
+    if (!toolDefinition.isTargetSupported(this._target)) {
+      return;
+    }
+
+    let tabs = this.doc.getElementById("toolbox-tabs");
+    let deck = this.doc.getElementById("toolbox-deck");
+
+    let id = toolDefinition.id;
+
+    let radio = this.doc.createElement("radio");
+    radio.setAttribute("label", toolDefinition.label);
+    radio.className = "toolbox-tab devtools-tab";
+    radio.id = "toolbox-tab-" + id;
+    radio.setAttribute("toolid", id);
+
+    let ordinal = (typeof toolDefinition.ordinal == "number") ?
+                  toolDefinition.ordinal : MAX_ORDINAL;
+    radio.setAttribute("ordinal", ordinal);
+
+    radio.addEventListener("command", function(id) {
+      this.selectTool(id);
+    }.bind(this, id));
+
+    let vbox = this.doc.createElement("vbox");
+    vbox.className = "toolbox-panel";
+    vbox.id = "toolbox-panel-" + id;
+
+    tabs.appendChild(radio);
+    deck.appendChild(vbox);
+  },
+
+  /**
+   * Switch to the tool with the given id
+   *
+   * @param {string} id
+   *        The id of the tool to switch to
+   */
+  selectTool: function TBOX_selectTool(id) {
+    if (!this.isReady) {
+      throw new Error("Can't select tool, wait for toolbox 'ready' event");
+    }
+    let tab = this.doc.getElementById("toolbox-tab-" + id);
+
+    if (!tab) {
+      throw new Error("No tool found");
+    }
+
+    let tabstrip = this.doc.getElementById("toolbox-tabs");
+
+    // select the right tab
+    let index = -1;
+    let tabs = tabstrip.childNodes;
+    for (let i = 0; i < tabs.length; i++) {
+      if (tabs[i] === tab) {
+        index = i;
+        break;
+      }
+    }
+    tabstrip.selectedIndex = index;
+
+    // and select the right iframe
+    let deck = this.doc.getElementById("toolbox-deck");
+    deck.selectedIndex = index;
+
+    let definition = gDevTools.getToolDefinitions().get(id);
+
+    let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
+    if (!iframe) {
+      iframe = this.doc.createElement("iframe");
+      iframe.className = "toolbox-panel-iframe";
+      iframe.id = "toolbox-panel-iframe-" + id;
+      iframe.setAttribute("flex", 1);
+
+      let vbox = this.doc.getElementById("toolbox-panel-" + id);
+      vbox.appendChild(iframe);
+
+      let boundLoad = function() {
+        iframe.removeEventListener("DOMContentLoaded", boundLoad, true);
+        let panel = definition.build(iframe.contentWindow, this);
+        this._toolPanels.set(id, panel);
+
+        let panelReady = function() {
+          this.emit(id + "-ready", panel);
+          this.emit("select", id);
+          this.emit(id + "-selected", panel);
+          gDevTools.emit(id + "-ready", this, panel);
+        }.bind(this);
+
+        if (panel.isReady) {
+          panelReady();
+        } else {
+          panel.once("ready", panelReady);
+        }
+      }.bind(this);
+
+      iframe.addEventListener("DOMContentLoaded", boundLoad, true);
+      iframe.setAttribute("src", definition.url);
+    } else {
+      let panel = this._toolPanels.get(id);
+      // only emit 'select' event if the iframe has been loaded
+      if (panel) {
+        this.emit("select", id);
+        this.emit(id + "-selected", panel);
+      }
+    }
+
+    Services.prefs.setCharPref(this._prefs.LAST_TOOL, id);
+
+    this._currentToolId = id;
+  },
+
+  /**
+   * Create a host object based on the given host type.
+   *
+   * @param {string} hostType
+   *        The host type of the new host object
+   *
+   * @return {Host} host
+   *        The created host object
+   */
+  _createHost: function TBOX_createHost(hostType) {
+    let hostTab = this._getHostTab();
+    if (!Hosts[hostType]) {
+      throw new Error('Unknown hostType: '+ hostType);
+    }
+    let newHost = new Hosts[hostType](hostTab);
+
+    // clean up the toolbox if its window is closed
+    newHost.on("window-closed", this.destroy);
+
+    return newHost;
+  },
+
+  /**
+   * Switch to a new host for the toolbox UI. E.g.
+   * bottom, sidebar, separate window.
+   *
+   * @param {string} hostType
+   *        The host type of the new host object
+   */
+  _switchToHost: function TBOX_switchToHost(hostType) {
+    if (hostType == this._host.type) {
+      return;
+    }
+
+    let newHost = this._createHost(hostType);
+
+    newHost.once("ready", function(event, iframe) {
+      // change toolbox document's parent to the new host
+      iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner);
+      iframe.swapFrameLoaders(this.frame);
+
+      this._host.off("window-closed", this.destroy);
+      this._host.destroy();
+
+      this._host = newHost;
+
+      Services.prefs.setCharPref(this._prefs.LAST_HOST, this._host.type);
+
+      this._buildDockButtons();
+
+      this.emit("host-changed");
+    }.bind(this));
+
+    newHost.open();
+  },
+
+  /**
+   * Get the most appropriate host tab, either the target or the current tab
+   */
+  _getHostTab: function TBOX_getHostTab() {
+    if (!this._target.isRemote && !this._target.isChrome) {
+      return this._target.tab;
+    } else {
+      let win = Services.wm.getMostRecentWindow("navigator:browser");
+      return win.gBrowser.selectedTab;
+    }
+  },
+
+  /**
+   * Handler for the tool-registered event.
+   * @param  {string} event
+   *         Name of the event ("tool-registered")
+   * @param  {string} toolId
+   *         Id of the tool that was registered
+   */
+  _toolRegistered: function TBOX_toolRegistered(event, toolId) {
+    let defs = gDevTools.getToolDefinitions();
+    let tool = defs.get(toolId);
+
+    this._buildTabForTool(tool);
+  },
+
+  /**
+   * Handler for the tool-unregistered event.
+   * @param  {string} event
+   *         Name of the event ("tool-unregistered")
+   * @param  {string} toolId
+   *         Id of the tool that was unregistered
+   */
+  _toolUnregistered: function TBOX_toolUnregistered(event, toolId) {
+    let radio = this.doc.getElementById("toolbox-tab-" + toolId);
+    let panel = this.doc.getElementById("toolbox-panel-" + toolId);
+
+    if (this._currentToolId == toolId) {
+      let nextToolName = null;
+      if (radio.nextSibling) {
+        nextToolName = radio.nextSibling.getAttribute("toolid");
+      }
+      if (radio.previousSibling) {
+        nextToolName = radio.previousSibling.getAttribute("toolid");
+      }
+      if (nextToolName) {
+        this.selectTool(nextToolName);
+      }
+    }
+
+    if (radio) {
+      radio.parentNode.removeChild(radio);
+    }
+
+    if (panel) {
+      panel.parentNode.removeChild(panel);
+    }
+
+    if (this._toolPanels.has(toolId)) {
+      let instance = this._toolPanels.get(toolId);
+      instance.destroy();
+      this._toolPanels.delete(toolId);
+    }
+  },
+
+
+  /**
+   * Get the toolbox's notification box
+   *
+   * @return The notification box element.
+   */
+  getNotificationBox: function TBOX_getNotificationBox() {
+    return this.doc.getElementById("toolbox-notificationbox");
+  },
+
+  /**
+   * Remove all UI elements, detach from target and clear up
+   */
+  destroy: function TBOX_destroy() {
+    if (this._destroyed) {
+      return;
+    }
+
+    // Remote targets need to be notified that the toolbox is being torn down.
+    if (this._target && this._target.isRemote) {
+      this._target.destroy();
+    }
+    this._target = null;
+
+    for (let [id, panel] of this._toolPanels) {
+      panel.destroy();
+    }
+
+    this._host.destroy();
+
+    gDevTools.off("tool-registered", this._toolRegistered);
+    gDevTools.off("tool-unregistered", this._toolUnregistered);
+
+    this._destroyed = true;
+    this.emit("destroyed");
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/ToolboxHosts.jsm
@@ -0,0 +1,208 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+
+this.EXPORTED_SYMBOLS = [ "Hosts" ];
+
+/**
+ * A toolbox host represents an object that contains a toolbox (e.g. the
+ * sidebar or a separate window). Any host object should implement the
+ * following functions:
+ *
+ * open() - create the UI and emit a 'ready' event when the UI is ready to use
+ * destroy() - destroy the host's UI
+ */
+
+this.Hosts = {
+  "bottom": BottomHost,
+  "side": SidebarHost,
+  "window": WindowHost
+}
+
+/**
+ * Host object for the dock on the bottom of the browser
+ */
+function BottomHost(hostTab) {
+  this.hostTab = hostTab;
+
+  new EventEmitter(this);
+}
+
+BottomHost.prototype = {
+  type: "bottom",
+
+  heightPref: "devtools.toolbox.footer.height",
+
+  /**
+   * Create a box at the bottom of the host tab.
+   */
+  open: function BH_open() {
+    let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
+    let ownerDocument = gBrowser.ownerDocument;
+
+    this._splitter = ownerDocument.createElement("splitter");
+    this._splitter.setAttribute("class", "devtools-horizontal-splitter");
+
+    this.frame = ownerDocument.createElement("iframe");
+    this.frame.id = "devtools-toolbox-bottom-iframe";
+    this.frame.height = Services.prefs.getIntPref(this.heightPref);
+
+    this._nbox = gBrowser.getNotificationBox(this.hostTab.linkedBrowser);
+    this._nbox.appendChild(this._splitter);
+    this._nbox.appendChild(this.frame);
+
+    let frameLoad = function() {
+      this.frame.removeEventListener("DOMContentLoaded", frameLoad, true);
+      this.emit("ready", this.frame);
+    }.bind(this);
+
+    this.frame.addEventListener("DOMContentLoaded", frameLoad, true);
+
+    // we have to load something so we can switch documents if we have to
+    this.frame.setAttribute("src", "about:blank");
+
+    focusTab(this.hostTab);
+  },
+
+  /**
+   * Destroy the bottom dock.
+   */
+  destroy: function BH_destroy() {
+    if (this._destroyed) {
+      return;
+    }
+    this._destroyed = true;
+    Services.prefs.setIntPref(this.heightPref, this.frame.height);
+
+    this._nbox.removeChild(this._splitter);
+    this._nbox.removeChild(this.frame);
+  }
+}
+
+
+/**
+ * Host object for the in-browser sidebar
+ */
+function SidebarHost(hostTab) {
+  this.hostTab = hostTab;
+
+  new EventEmitter(this);
+}
+
+SidebarHost.prototype = {
+  type: "side",
+
+  widthPref: "devtools.toolbox.sidebar.width",
+
+  /**
+   * Create a box in the sidebar of the host tab.
+   */
+  open: function RH_open() {
+    let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
+    let ownerDocument = gBrowser.ownerDocument;
+
+    this._splitter = ownerDocument.createElement("splitter");
+    this._splitter.setAttribute("class", "devtools-side-splitter");
+
+    this.frame = ownerDocument.createElement("iframe");
+    this.frame.id = "devtools-toolbox-side-iframe";
+    this.frame.width = Services.prefs.getIntPref(this.widthPref);
+
+    this._sidebar = gBrowser.getSidebarContainer(this.hostTab.linkedBrowser);
+    this._sidebar.appendChild(this._splitter);
+    this._sidebar.appendChild(this.frame);
+
+    let frameLoad = function() {
+      this.frame.removeEventListener("DOMContentLoaded", frameLoad, true);
+      this.emit("ready", this.frame);
+    }.bind(this);
+
+    this.frame.addEventListener("DOMContentLoaded", frameLoad, true);
+    this.frame.setAttribute("src", "about:blank");
+
+    focusTab(this.hostTab);
+  },
+
+  /**
+   * Destroy the sidebar.
+   */
+  destroy: function RH_destroy() {
+    Services.prefs.setIntPref(this.widthPref, this.frame.width);
+
+    this._sidebar.removeChild(this._splitter);
+    this._sidebar.removeChild(this.frame);
+  }
+}
+
+/**
+ * Host object for the toolbox in a separate window
+ */
+function WindowHost() {
+  this._boundUnload = this._boundUnload.bind(this);
+
+  new EventEmitter(this);
+}
+
+WindowHost.prototype = {
+  type: "window",
+
+  WINDOW_URL: "chrome://browser/content/devtools/framework/toolbox-window.xul",
+
+  /**
+   * Create a new xul window to contain the toolbox.
+   */
+  open: function WH_open() {
+    let flags = "chrome,centerscreen,resizable,dialog=no";
+    let win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
+                                     flags, null);
+
+    let frameLoad = function(event) {
+      win.removeEventListener("load", frameLoad, true);
+      this.frame = win.document.getElementById("toolbox-iframe");
+      this.emit("ready", this.frame);
+    }.bind(this);
+
+    win.addEventListener("load", frameLoad, true);
+    win.addEventListener("unload", this._boundUnload);
+
+    win.focus();
+
+    this._window = win;
+  },
+
+  /**
+   * Catch the user closing the window.
+   */
+  _boundUnload: function(event) {
+    if (event.target.location != this.WINDOW_URL) {
+      return;
+    }
+    this._window.removeEventListener("unload", this._boundUnload);
+
+    this.emit("window-closed");
+  },
+
+  /**
+   * Destroy the window.
+   */
+  destroy: function WH_destroy() {
+    this._window.removeEventListener("unload", this._boundUnload);
+    this._window.close();
+  }
+}
+
+/**
+ *  Switch to the given tab in a browser and focus the browser window
+ */
+function focusTab(tab) {
+  let browserWindow = tab.ownerDocument.defaultView;
+  browserWindow.focus();
+  browserWindow.gBrowser.selectedTab = tab;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/connect/connect.css
@@ -0,0 +1,87 @@
+html {
+  background: url("chrome://browser/skin/newtab/noise.png");
+}
+
+body {
+  font-family: Arial;
+  padding: 20px;
+  border-radius: 3px;
+  max-width: 600px;
+  min-height: 400px;
+  margin: 10px auto 0;
+}
+
+label {
+  display: block;
+  margin: 10px;
+  font-size: 0;
+}
+
+label > span {
+  display: inline-block;
+  min-width: 150px;
+  font-size: 0.8rem;
+  text-align: right;
+  margin-right: 10px;
+}
+
+#submit {
+  margin-left: 160px;
+}
+
+
+#actors, #connection-form {
+  margin: 20px;
+}
+
+input {
+  border: 1px solid grey;
+}
+
+#connection-form,
+#connecting,
+#actors-list {
+  display: none;
+}
+
+body:not(.actors-mode):not(.connecting) > #connection-form {
+  display: block;
+}
+
+body.actors-mode > #actors-list {
+  display: block;
+}
+
+body.connecting > #connecting {
+  display: block;
+}
+
+#connecting {
+  text-align: center;
+}
+
+#throbber {
+  height: 7px; width: 7px;
+  border-radius: 50%;
+  background: black;
+  display: inline-block;
+  animation-duration: 0.6s;
+  animation-name: anim;
+  animation-direction: alternate;
+  animation-iteration-count: infinite;
+  animation-timing-function: linear;
+}
+@keyframes anim {to {
+    transform: scale(0.5) rotate(0.1deg);
+}}
+
+#actors {
+  padding-left: 0;
+  font-size: 0.9rem;
+}
+
+#actors > a {
+  display: block;
+  margin: 5px;
+  padding: 5px;
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/connect/connect.js
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const Cu = Components.utils;
+Cu.import("resource:///modules/devtools/Target.jsm");
+Cu.import("resource:///modules/devtools/Toolbox.jsm");
+Cu.import("resource:///modules/devtools/gDevTools.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
+
+let gClient;
+
+function submit() {
+  document.body.classList.add("connecting");
+
+  let host = document.getElementById("host").value;
+  let port = document.getElementById("port").value;
+  if (!host) {
+    host = Services.prefs.getCharPref("devtools.debugger.remote-host");
+  } else {
+    Services.prefs.setCharPref("devtools.debugger.remote-host", host);
+  }
+  if (!port) {
+    port = Services.prefs.getIntPref("devtools.debugger.remote-port");
+  } else {
+    Services.prefs.setIntPref("devtools.debugger.remote-port", port);
+  }
+
+  let transport = debuggerSocketConnect(host, port);
+  let client = gClient = new DebuggerClient(transport);
+
+  client.connect(function(aType, aTraits) {
+    client.listTabs(function(aResponse) {
+      document.body.classList.remove("connecting");
+      document.body.classList.add("actors-mode");
+
+      let parent = document.getElementById("actors");
+      let focusSet = false;
+
+      // Add Global Process debugging...
+      let globals = JSON.parse(JSON.stringify(aResponse));
+      delete globals.tabs;
+      delete globals.selected;
+      // ...only if there are appropriate actors (a 'from' property will always
+      // be there).
+      if (Object.keys(globals).length > 1) {
+        let a = document.createElement("a");
+        a.onclick = function() {
+          connect(globals, true);
+        }
+
+        a.title = a.textContent = "Remote process";
+        a.href = "#";
+
+        parent.appendChild(a);
+      }
+
+      // Add one entry for each open tab.
+      if (aResponse.tabs.length > 0) {
+        let header = document.createElement("div");
+        header.innerHTML = "Tabs:";
+        parent.appendChild(header);
+      }
+      for (let i = 0; i < aResponse.tabs.length; i++) {
+        let tab = aResponse.tabs[i];
+
+        let a = document.createElement("a");
+        a.onclick = function() {
+          connect(tab);
+        }
+
+        a.title = a.textContent = tab.title;
+        a.href = "#";
+
+        if (i == aResponse.selected) {
+          a.title += " [*]";
+          a.textContent = a.title;
+        }
+
+        parent.appendChild(a);
+
+        if (!focusSet) {
+          a.focus();
+          focusSet = true;
+        }
+      }
+    });
+  });
+}
+
+function connect(form, chrome=false) {
+  let target = TargetFactory.forRemote(form, gClient, chrome);
+  gDevTools.openToolbox(target, Toolbox.HostType.WINDOW, "webconsole");
+  window.close();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/connect/connect.xhtml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE html [
+<!ENTITY % connectionDTD SYSTEM "chrome://browser/locale/devtools/connection-screen.dtd" >
+ %connectionDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <head>
+    <title>&title;</title>
+    <link rel="stylesheet" href="chrome://browser/content/devtools/connect.css" type="text/css"/>
+    <script type="application/javascript;version=1.8" src="connect.js"></script>
+  </head>
+  <body>
+    <p>
+    </p>
+    <section id="connection-form">
+      <form onsubmit="window.submit()" action="#">
+        <label>
+          <span>&host;</span>
+          <input id="host" type="text" placeholder="localhost"></input>
+        </label>
+        <label>
+          <span>&port;</span>
+          <input id="port" type="number" placeholder="6000"></input>
+        </label>
+        <label>
+          <input id="submit" type="submit" value="&connect;"></input>
+        </label>
+      </form>
+    </section>
+    <section id="actors-list">
+      <p>&availability;</p>
+      <ul id="actors"></ul>
+    </section>
+    <section id="connecting">
+      <p>&connecting;</p>
+      <div id="throbber"></div>
+    </section>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -0,0 +1,546 @@
+/* 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.EXPORTED_SYMBOLS = [ "gDevTools", "DevTools", "DevToolsXULCommands" ];
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
+Cu.import("resource:///modules/devtools/ToolDefinitions.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Toolbox",
+  "resource:///modules/devtools/Toolbox.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+  "resource:///modules/devtools/Target.jsm");
+
+const FORBIDDEN_IDS = new Set("toolbox", "");
+
+/**
+ * DevTools is a class that represents a set of developer tools, it holds a
+ * set of tools and keeps track of open toolboxes in the browser.
+ */
+this.DevTools = function DevTools() {
+  this._tools = new Map();
+  this._toolboxes = new Map();
+
+  // destroy() is an observer's handler so we need to preserve context.
+  this.destroy = this.destroy.bind(this);
+
+  this._trackedBrowserWindows = new Set();
+
+  // Bind _updateMenuCheckbox() to preserve context.
+  this._updateMenuCheckbox = this._updateMenuCheckbox.bind(this);
+
+  new EventEmitter(this);
+
+  Services.obs.addObserver(this.destroy, "quit-application", false);
+
+  /**
+   * Register the set of default tools
+   */
+  for (let definition of defaultTools) {
+    this.registerTool(definition);
+  }
+}
+
+DevTools.prototype = {
+  /**
+   * Register a new developer tool.
+   *
+   * A definition is a light object that holds different information about a
+   * developer tool. This object is not supposed to have any operational code.
+   * See it as a "manifest".
+   * The only actual code lives in the build() function, which will be used to
+   * start an instance of this tool.
+   *
+   * Each toolDefinition has the following properties:
+   * - id: Unique identifier for this tool (string|required)
+   * - killswitch: Property name to allow us to turn this tool on/off globally
+   *               (string|required) (TODO: default to devtools.{id}.enabled?)
+   * - icon: URL pointing to a graphic which will be used as the src for an
+   *         16x16 img tag (string|required)
+   * - url: URL pointing to a XUL/XHTML document containing the user interface
+   *        (string|required)
+   * - label: Localized name for the tool to be displayed to the user
+   *          (string|required)
+   * - build: Function that takes an iframe, which has been populated with the
+   *          markup from |url|, and also the toolbox containing the panel.
+   *          And returns an instance of ToolPanel (function|required)
+   */
+  registerTool: function DT_registerTool(toolDefinition) {
+    let toolId = toolDefinition.id;
+
+    if (!toolId || FORBIDDEN_IDS.has(toolId)) {
+      throw new Error("Invalid definition.id");
+    }
+
+    toolDefinition.killswitch = toolDefinition.killswitch ||
+      "devtools." + toolId + ".enabled";
+    this._tools.set(toolId, toolDefinition);
+
+    this._addToolToWindows(toolDefinition);
+
+    this.emit("tool-registered", toolId);
+  },
+
+  /**
+   * Removes all tools that match the given |toolId|
+   * Needed so that add-ons can remove themselves when they are deactivated
+   *
+   * @param {string} toolId
+   *        id of the tool to unregister
+   */
+  unregisterTool: function DT_unregisterTool(toolId) {
+    this._tools.delete(toolId);
+
+    this._removeToolFromWindows(toolId);
+
+    this.emit("tool-unregistered", toolId);
+  },
+
+  /**
+   * Allow ToolBoxes to get at the list of tools that they should populate
+   * themselves with.
+   *
+   * @return {Map} tools
+   *         A map of the the tool definitions registered in this instance
+   */
+  getToolDefinitions: function DT_getToolDefinitions() {
+    let tools = new Map();
+
+    for (let [key, value] of this._tools) {
+      let enabled;
+
+      try {
+        enabled = Services.prefs.getBoolPref(value.killswitch);
+      } catch(e) {
+        enabled = true;
+      }
+
+      if (enabled) {
+        tools.set(key, value);
+      }
+    }
+    return tools;
+  },
+
+  /**
+   * Create a toolbox to debug |target| using a window displayed in |hostType|
+   * (optionally with |defaultToolId| opened)
+   *
+   * @param {Target} target
+   *         The target the toolbox will debug
+   * @param {Toolbox.HostType} hostType
+   *        The type of host (bottom, top, side)
+   * @param {string} defaultToolId
+   *        The id of the initial tool to show
+   *
+   * @return {Toolbox} toolbox
+   *        The toolbox that was opened
+   */
+  openToolbox: function DT_openToolbox(target, hostType, defaultToolId) {
+    if (this._toolboxes.has(target)) {
+      // only allow one toolbox per target
+      return this._toolboxes.get(target);
+    }
+
+    let tb = new Toolbox(target, hostType, defaultToolId);
+
+    this._toolboxes.set(target, tb);
+    tb.once("destroyed", function() {
+      this._toolboxes.delete(target);
+      this._updateMenuCheckbox();
+      this.emit("toolbox-destroyed", target);
+    }.bind(this));
+
+    tb.once("ready", function() {
+      this.emit("toolbox-ready", tb);
+      this._updateMenuCheckbox();
+    }.bind(this));
+
+    tb.open();
+
+    return tb;
+  },
+
+  /**
+   * Close the toolbox for a given target
+   */
+  closeToolbox: function DT_closeToolbox(target) {
+    let toolbox = this._toolboxes.get(target);
+    if (toolbox == null) {
+      return;
+    }
+    toolbox.destroy();
+  },
+
+  /**
+   * Open the toolbox for a specific target (not tab).
+   * FIXME: We should probably merge this function and openToolbox
+   *
+   * @param  {Target} target
+   *         The target that the toolbox should be debugging
+   * @param  {String} toolId
+   *         The id of the tool to open
+   *
+   * @return {Toolbox} toolbox
+   *         The toolbox that has been opened
+   */
+  openToolboxForTab: function DT_openToolboxForTab(target, toolId) {
+    let tb = this.getToolboxForTarget(target);
+
+    if (tb) {
+      tb.selectTool(toolId);
+    } else {
+      tb = this.openToolbox(target, null, toolId);
+    }
+    return tb;
+  },
+
+  /**
+   * This function is for the benefit of command#Tools:DevToolbox in
+   * browser/base/content/browser-sets.inc and should not be used outside
+   * of there
+   */
+  toggleToolboxCommand: function(gBrowser, toolId=null) {
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    this.toggleToolboxForTarget(target, toolId);
+  },
+
+  /**
+   * Toggle a toolbox for the given target.
+   *
+   * @param  {Target} target
+   *         The target the toolbox is debugging
+   * @param  {string} toolId
+   *         The id of the tool to show in the toolbox, if it's to be opened.
+   */
+  toggleToolboxForTarget: function DT_toggleToolboxForTarget(target, toolId) {
+    let tb = this.getToolboxForTarget(target);
+
+    if (tb /* FIXME: && tool is showing */ ) {
+      tb.destroy();
+    } else {
+      this.openToolboxForTab(target, toolId);
+    }
+  },
+
+  /**
+   * Return the toolbox for a given target.
+   *
+   * @param  {object} target
+   *         Target value e.g. the target that owns this toolbox
+   *
+   * @return {Toolbox} toolbox
+   *         The toobox that is debugging the given target
+   */
+  getToolboxForTarget: function DT_getToolboxForTarget(target) {
+    return this._toolboxes.get(target);
+  },
+
+  /**
+   * Return a tool panel for a given tool and target.
+   *
+   * @param  {String} toolId
+   *         The id of the tool to open.
+   * @param  {object} target
+   *         The toolbox's target.
+   *
+   * @return {ToolPanel} panel
+   *         Panel for the tool with the toolid
+   */
+  getPanelForTarget: function DT_getPanelForTarget(toolId, target) {
+    let toolbox = this.getToolboxForTarget(target);
+    if (!toolbox) {
+      return undefined;
+    }
+    return toolbox.getToolPanels().get(toolId);
+  },
+
+  /**
+   * 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
+   */
+  registerBrowserWindow: function DT_registerBrowserWindow(win) {
+    this._trackedBrowserWindows.add(win);
+    this._addAllToolsToMenu(win.document);
+
+    let tabContainer = win.document.getElementById("tabbrowser-tabs")
+    tabContainer.addEventListener("TabSelect", this._updateMenuCheckbox, false);
+  },
+
+  /**
+   * Add the menuitem for a tool to all open browser windows.
+   *
+   * @param {object} toolDefinition
+   *        properties of the tool to add
+   */
+  _addToolToWindows: function DT_addToolToWindows(toolDefinition) {
+    for (let win of this._trackedBrowserWindows) {
+      this._addToolToMenu(toolDefinition, win.document);
+    }
+  },
+
+  /**
+   * Add all tools to the developer tools menu of a window.
+   *
+   * @param {XULDocument} doc
+   *        The document to which the tool items are to be added.
+   */
+  _addAllToolsToMenu: function DT_addAllToolsToMenu(doc) {
+    let fragCommands = doc.createDocumentFragment();
+    let fragKeys = doc.createDocumentFragment();
+    let fragBroadcasters = doc.createDocumentFragment();
+    let fragAppMenuItems = doc.createDocumentFragment();
+    let fragMenuItems = doc.createDocumentFragment();
+
+    for (let [key, toolDefinition] of this._tools) {
+      let frags = this._addToolToMenu(toolDefinition, doc, true);
+
+      if (!frags) {
+        return;
+      }
+
+      let [cmd, key, bc, appmenuitem, menuitem] = frags;
+
+      fragCommands.appendChild(cmd);
+      if (key) {
+        fragKeys.appendChild(key);
+      }
+      fragBroadcasters.appendChild(bc);
+      fragAppMenuItems.appendChild(appmenuitem);
+      fragMenuItems.appendChild(menuitem);
+    }
+
+    let mcs = doc.getElementById("mainCommandSet");
+    mcs.appendChild(fragCommands);
+
+    let mks = doc.getElementById("mainKeyset");
+    mks.appendChild(fragKeys);
+
+    let mbs = doc.getElementById("mainBroadcasterSet");
+    mbs.appendChild(fragBroadcasters);
+
+    let amp = doc.getElementById("appmenu_webDeveloper_popup");
+    if (amp) {
+      let amps = doc.getElementById("appmenu_devtools_separator");
+      amp.insertBefore(fragAppMenuItems, amps);
+    }
+
+    let mp = doc.getElementById("menuWebDeveloperPopup");
+    let mps = doc.getElementById("menu_devtools_separator");
+    mp.insertBefore(fragMenuItems, mps);
+  },
+
+  /**
+   * Add a menu entry for a tool definition
+   *
+   * @param {string} toolDefinition
+   *        Tool definition of the tool to add a menu entry.
+   * @param {XULDocument} doc
+   *        The document to which the tool menu item is to be added.
+   * @param {Boolean} [noAppend]
+   *        Return an array of elements instead of appending them to the
+   *        document. Default is false.
+   */
+  _addToolToMenu: function DT_addToolToMenu(toolDefinition, doc, noAppend) {
+    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",
+        'gDevTools.toggleToolboxCommand(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("oncommand",
+          'gDevTools.toggleToolboxCommand(gBrowser, "' + id + '");');
+      key.setAttribute("modifiers", toolDefinition.modifiers);
+    }
+
+    let bc = doc.createElement("broadcaster");
+    bc.id = "devtoolsMenuBroadcaster_" + id;
+    bc.setAttribute("label", toolDefinition.label);
+    bc.setAttribute("command", "Tools:" + id);
+
+    if (key) {
+      bc.setAttribute("key", "key_" + id);
+    }
+
+    let appmenuitem = doc.createElement("menuitem");
+    appmenuitem.id = "appmenuitem_" + id;
+    appmenuitem.setAttribute("observes", "devtoolsMenuBroadcaster_" + id);
+
+    let menuitem = doc.createElement("menuitem");
+    menuitem.id = "menuitem_" + id;
+    menuitem.setAttribute("observes", "devtoolsMenuBroadcaster_" + id);
+
+    if (toolDefinition.accesskey) {
+      menuitem.setAttribute("accesskey", toolDefinition.accesskey);
+    }
+
+    if (noAppend) {
+      return [cmd, key, bc, appmenuitem, menuitem];
+    } else {
+      let mcs = doc.getElementById("mainCommandSet");
+      mcs.appendChild(cmd);
+
+      if (key) {
+        let mks = doc.getElementById("mainKeyset");
+        mks.appendChild(key);
+      }
+
+      let mbs = doc.getElementById("mainBroadcasterSet");
+      mbs.appendChild(bc);
+
+      let amp = doc.getElementById("appmenu_webDeveloper_popup");
+      if (amp) {
+        let amps = doc.getElementById("appmenu_devtools_separator");
+        amp.insertBefore(appmenuitem, amps);
+      }
+
+      let mp = doc.getElementById("menuWebDeveloperPopup");
+      let mps = doc.getElementById("menu_devtools_separator");
+      mp.insertBefore(menuitem, mps);
+    }
+  },
+
+  /**
+   * Update the "Toggle Toolbox" checkbox in the developer tools menu. This is
+   * called when a toolbox is created or destroyed.
+   */
+  _updateMenuCheckbox: function DT_updateMenuCheckbox() {
+    for (let win of this._trackedBrowserWindows) {
+
+      let hasToolbox = false;
+      if (TargetFactory.isKnownTab(win.gBrowser.selectedTab)) {
+        let target = TargetFactory.forTab(win.gBrowser.selectedTab);
+        if (this._toolboxes.has(target)) {
+          hasToolbox = true;
+        }
+      }
+
+      let broadcaster = win.document.getElementById("devtoolsMenuBroadcaster_DevToolbox");
+      if (hasToolbox) {
+        broadcaster.setAttribute("checked", "true");
+      } else {
+        broadcaster.removeAttribute("checked");
+      }
+    }
+  },
+
+  /**
+   * Remove the menuitem for a tool to all open browser windows.
+   *
+   * @param {object} toolId
+   *        id of the tool to remove
+   */
+  _removeToolFromWindows: function DT_removeToolFromWindows(toolId) {
+    for (let win of this._trackedBrowserWindows) {
+      this._removeToolFromMenu(toolId, win.document);
+    }
+  },
+
+  /**
+   * Remove a tool's menuitem from a window
+   *
+   * @param {string} toolId
+   *        Id of the tool to add a menu entry for
+   * @param {XULDocument} doc
+   *        The document to which the tool menu item is to be removed from
+   */
+  _removeToolFromMenu: function DT_removeToolFromMenu(toolId, doc) {
+    let command = doc.getElementById("Tools:" + toolId);
+    command.parentNode.removeChild(command);
+
+    let key = doc.getElementById("key_" + toolId);
+    if (key) {
+      key.parentNode.removeChild(key);
+    }
+
+    let bc = doc.getElementById("devtoolsMenuBroadcaster_" + toolId);
+    bc.parentNode.removeChild(bc);
+
+    /*
+    // FIXME: item is null in testing. This is the only place to use
+    // "appmenu_devToolbar" + toolId, so it seems clear that this is wrong
+    let item = doc.getElementById("appmenu_devToolbar" + toolId);
+    item.parentNode.removeChild(item);
+    */
+  },
+
+  /**
+   * Called on browser unload to remove menu entries, toolboxes and event
+   * listeners from the closed browser window.
+   *
+   * @param  {XULWindow} win
+   *         The window containing the menu entry
+   */
+  forgetBrowserWindow: function DT_forgetBrowserWindow(win) {
+    if (!this._tools) {
+      return;
+    }
+
+    this._trackedBrowserWindows.delete(win);
+
+    // Destroy toolboxes for closed window
+    for (let [target, toolbox] of this._toolboxes) {
+      if (toolbox.frame.ownerDocument.defaultView == win) {
+        toolbox.destroy();
+      }
+    }
+
+    let tabContainer = win.document.getElementById("tabbrowser-tabs")
+    tabContainer.removeEventListener("TabSelect",
+                                     this._updateMenuCheckbox, false);
+  },
+
+  /**
+   * All browser windows have been closed, tidy up remaining objects.
+   */
+  destroy: function() {
+    Services.obs.removeObserver(this.destroy, "quit-application");
+
+    delete this._trackedBrowserWindows;
+    delete this._tools;
+    delete this._toolboxes;
+  },
+};
+
+/**
+ * gDevTools is a singleton that controls the Firefox Developer Tools.
+ *
+ * It is an instance of a DevTools class that holds a set of tools. It has the
+ * same lifetime as the browser.
+ */
+this.gDevTools = new DevTools();
+
+/**
+ * DevToolsXULCommands exposes methods used by browser's <command>s.
+ */
+this.DevToolsXULCommands = {
+  openConnectScreen: function(gBrowser) {
+    gBrowser.selectedTab = gBrowser.addTab("chrome://browser/content/devtools/connect.xhtml");
+  },
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/Makefile.in
@@ -0,0 +1,26 @@
+# 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/.
+
+DEPTH			= @DEPTH@
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH			= @srcdir@
+relativesrcdir  = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_BROWSER_FILES = \
+		head.js \
+		browser_devtools_api.js \
+		browser_new_activation_workflow.js \
+		browser_toolbox_dynamic_registration.js \
+		browser_toolbox_hosts.js \
+		browser_toolbox_ready.js \
+		browser_toolbox_select_event.js \
+		browser_target_events.js \
+		browser_toolbox_tool_ready.js \
+		browser_toolbox_sidebar.js \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_devtools_api.js
@@ -0,0 +1,137 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests devtools API
+
+const Cu = Components.utils;
+const toolId = "test-tool";
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/EventEmitter.jsm", tempScope);
+let EventEmitter = tempScope.EventEmitter;
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+
+function test() {
+  addTab("about:blank", function(aBrowser, aTab) {
+    runTests(aTab);
+  });
+}
+
+function runTests(aTab) {
+  let toolDefinition = {
+    id: toolId,
+    isTargetSupported: function() true,
+    killswitch: "devtools.test-tool.enabled",
+    url: "about:blank",
+    label: "someLabel",
+    build: function(iframeWindow, toolbox) {
+      let panel = new DevToolPanel(iframeWindow, toolbox);
+      return panel;
+    },
+  };
+
+  ok(gDevTools, "gDevTools exists");
+  is(gDevTools.getToolDefinitions().has(toolId), false,
+    "The tool is not registered");
+
+  gDevTools.registerTool(toolDefinition);
+  is(gDevTools.getToolDefinitions().has(toolId), true,
+    "The tool is registered");
+
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  function onNewToolbox(event, toolboxFromEvent) {
+    let toolBoxes = gDevTools._toolboxes;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let tb = toolBoxes.get(target);
+    is(toolboxFromEvent, tb, "'toolbox-ready' event fired. Correct toolbox value.");
+    is(tb.target, target, "toolbox target is correct");
+    is(tb._host.hostTab, gBrowser.selectedTab, "toolbox host is correct");
+    gDevTools.once(toolId + "-ready", continueTests);
+  }
+
+  function onToolboxClosed(event, targetFromEvent) {
+    is(targetFromEvent, target, "'toolbox-destroyed' event fired. Correct tab value.");
+    finishUp();
+  }
+
+
+  gDevTools.once("toolbox-ready", onNewToolbox);
+  gDevTools.once("toolbox-destroyed", onToolboxClosed);
+
+  executeSoon(function() {
+    gDevTools.openToolbox(target, "bottom", toolId);
+  });
+}
+
+function continueTests(event, toolbox, panel) {
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  is(toolbox, gDevTools._toolboxes.get(target), "{toolId}-ready event received, with correct toolbox value");
+  is(panel, toolbox.getToolPanels().get(toolId), "panel value is correct");
+
+  is(toolbox.currentToolId, toolId, "toolbox _currentToolId is correct");
+
+  let toolDefinitions = gDevTools.getToolDefinitions();
+  is(toolDefinitions.has(toolId), true, "The tool is in gDevTools");
+
+  let toolDefinition = toolDefinitions.get(toolId);
+  is(toolDefinition.id, toolId, "toolDefinition id is correct");
+
+  gDevTools.unregisterTool(toolId);
+  is(gDevTools.getToolDefinitions().has(toolId), false,
+    "The tool is no longer registered");
+
+  toolbox.destroy();
+}
+
+function finishUp() {
+  tempScope = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+/**
+* When a Toolbox is started it creates a DevToolPanel for each of the tools
+* by calling toolDefinition.build(). The returned object should
+* at least implement these functions. They will be used by the ToolBox.
+*
+* There may be no benefit in doing this as an abstract type, but if nothing
+* else gives us a place to write documentation.
+*/
+function DevToolPanel(iframeWindow, toolbox) {
+  new EventEmitter(this);
+
+  this._toolbox = toolbox;
+
+  /*let doc = iframeWindow.document
+  let label = doc.createElement("label");
+  let textNode = doc.createTextNode("Some Tool");
+
+  label.appendChild(textNode);
+  doc.body.appendChild(label);*/
+
+  executeSoon(function() {
+    this.setReady();
+  }.bind(this));
+}
+
+DevToolPanel.prototype = {
+  get target() this._toolbox.target,
+
+  get toolbox() this._toolbox,
+
+  get isReady() this._isReady,
+
+  _isReady: false,
+
+  setReady: function() {
+    this._isReady = true;
+    this.emit("ready");
+  },
+
+  destroy: function DTI_destroy()
+  {
+
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_new_activation_workflow.js
@@ -0,0 +1,64 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests devtools API
+
+const Cu = Components.utils;
+
+let toolbox;
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+
+function test() {
+  addTab("about:blank", function(aBrowser, aTab) {
+    loadWebConsole(aTab);
+  });
+}
+
+function loadWebConsole(aTab) {
+  ok(gDevTools, "gDevTools exists");
+
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  toolbox = gDevTools.openToolbox(target, "bottom", "webconsole");
+  toolbox.once("webconsole-ready", checkToolLoading);
+}
+
+function checkToolLoading() {
+  is(toolbox.currentToolId, "webconsole", "The web console is selected");
+  selectAndCheckById("jsdebugger");
+  selectAndCheckById("styleeditor");
+  testToggle();
+}
+
+function selectAndCheckById(id) {
+  let doc = toolbox.frame.contentDocument;
+
+  toolbox.selectTool(id);
+  let tab = doc.getElementById("toolbox-tab-" + id);
+  is(tab.selected, true, "The " + id + " tab is selected");
+}
+
+function testToggle() {
+  toolbox.once("destroyed", function() {
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    toolbox = gDevTools.openToolbox(target, "bottom", "styleeditor");
+    toolbox.once("styleeditor-ready", checkStyleEditorLoaded);
+  }.bind(this));
+
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  gDevTools.toggleToolboxForTarget(target);
+}
+
+function checkStyleEditorLoaded() {
+  is(toolbox.currentToolId, "styleeditor", "The style editor is selected");
+  finishUp();
+}
+
+function finishUp() {
+  toolbox.destroy();
+  toolbox = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_target_events.js
@@ -0,0 +1,58 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+var TargetFactory = tempScope.TargetFactory;
+
+var target;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", onLoad, true);
+}
+
+function onLoad(evt) {
+  gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+
+  target = TargetFactory.forTab(gBrowser.selectedTab);
+
+  is(target.tab, gBrowser.selectedTab, "Target linked to the right tab.");
+
+  target.once("hidden", onHidden);
+  gBrowser.selectedTab = gBrowser.addTab();
+}
+
+function onHidden() {
+  ok(true, "Hidden event received");
+  target.once("visible", onVisible);
+  gBrowser.removeCurrentTab();
+}
+
+function onVisible() {
+  ok(true, "Visible event received");
+  target.once("will-navigate", onWillNavigate);
+  gBrowser.contentWindow.location = "data:text/html,test navigation";
+}
+
+function onWillNavigate(event, request) {
+  ok(true, "will-navigate event received");
+  target.once("navigate", onNavigate);
+}
+
+function onNavigate() {
+  ok(true, "navigate event received");
+  target.once("close", onClose);
+  gBrowser.removeCurrentTab();
+}
+
+function onClose() {
+  ok(true, "close event received");
+
+  target = null;
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_dynamic_registration.js
@@ -0,0 +1,112 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let toolbox;
+
+let temp = {};
+Cu.import("resource:///modules/devtools/Target.jsm", temp);
+let TargetFactory = temp.TargetFactory;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    openToolbox();
+  }, true);
+
+  content.location = "data:text/html,test for dynamically registering and unregistering tools";
+}
+
+function openToolbox()
+{
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  toolbox = gDevTools.openToolbox(target);
+
+  toolbox.once("ready", testRegister);
+}
+
+
+function testRegister()
+{
+  gDevTools.once("tool-registered", toolRegistered);
+
+  gDevTools.registerTool({
+    id: "test-tool",
+    label: "Test Tool",
+    isTargetSupported: function() true,
+    build: function() {}
+  });
+}
+
+function toolRegistered(event, toolId)
+{
+  is(toolId, "test-tool", "tool-registered event handler sent tool id");
+
+  ok(gDevTools.getToolDefinitions().has(toolId), "tool added to map");
+
+  // test that it appeared in the UI
+  let doc = toolbox.frame.contentDocument;
+  let tab = doc.getElementById("toolbox-tab-" + toolId);
+  ok(tab, "new tool's tab exists in toolbox UI");
+
+  let panel = doc.getElementById("toolbox-panel-" + toolId);
+  ok(panel, "new tool's panel exists in toolbox UI");
+
+  for (let win of getAllBrowserWindows()) {
+    let command = win.document.getElementById("Tools:" + toolId);
+    ok(command, "command for new tool added to every browser window");
+  }
+
+  // then unregister it
+  testUnregister();
+}
+
+function getAllBrowserWindows() {
+  let wins = [];
+  let enumerator = Services.wm.getEnumerator("navigator:browser");
+  while (enumerator.hasMoreElements()) {
+    wins.push(enumerator.getNext());
+  }
+  return wins;
+}
+
+function testUnregister()
+{
+  gDevTools.once("tool-unregistered", toolUnregistered);
+
+  gDevTools.unregisterTool("test-tool");
+}
+
+function toolUnregistered(event, toolId)
+{
+  is(toolId, "test-tool", "tool-unregistered event handler sent tool id");
+
+  ok(!gDevTools.getToolDefinitions().has(toolId), "tool removed from map");
+
+  // test that it disappeared from the UI
+  let doc = toolbox.frame.contentDocument;
+  let tab = doc.getElementById("toolbox-tab-" + toolId);
+  ok(!tab, "tool's tab was removed from the toolbox UI");
+
+  let panel = doc.getElementById("toolbox-panel-" + toolId);
+  ok(!panel, "tool's panel was removed from toolbox UI");
+
+  for (let win of getAllBrowserWindows()) {
+    let command = win.document.getElementById("Tools:" + toolId);
+    ok(!command, "command removed from every browser window");
+  }
+
+  cleanup();
+}
+
+function cleanup()
+{
+  toolbox.destroy();
+  toolbox = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_hosts.js
@@ -0,0 +1,135 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let temp = {}
+Cu.import("resource:///modules/devtools/gDevTools.jsm", temp);
+let DevTools = temp.DevTools;
+
+Cu.import("resource:///modules/devtools/Toolbox.jsm", temp);
+let Toolbox = temp.Toolbox;
+
+Cu.import("resource:///modules/devtools/Target.jsm", temp);
+let TargetFactory = temp.TargetFactory;
+
+let toolbox;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    openToolbox(testBottomHost);
+  }, true);
+
+  content.location = "data:text/html,test for opening toolbox in different hosts";
+}
+
+function openToolbox(callback)
+{
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  gDevTools.toggleToolboxForTarget(target);
+
+  toolbox = gDevTools.getToolboxForTarget(target);
+  toolbox.once("ready", callback);
+}
+
+function testBottomHost()
+{
+  checkHostType(Toolbox.HostType.BOTTOM);
+
+  // test UI presence
+  let iframe = document.getElementById("devtools-toolbox-bottom-iframe");
+  ok(iframe, "toolbox bottom iframe exists");
+
+  checkToolboxLoaded(iframe);
+
+  toolbox.once("host-changed", testSidebarHost);
+  toolbox.hostType = Toolbox.HostType.SIDE;
+}
+
+function testSidebarHost()
+{
+  checkHostType(Toolbox.HostType.SIDE);
+
+  // test UI presence
+  let bottom = document.getElementById("devtools-toolbox-bottom-iframe");
+  ok(!bottom, "toolbox bottom iframe doesn't exist");
+
+  let iframe = document.getElementById("devtools-toolbox-side-iframe");
+  ok(iframe, "toolbox side iframe exists");
+
+  checkToolboxLoaded(iframe);
+
+  toolbox.once("host-changed", testWindowHost);
+  toolbox.hostType = Toolbox.HostType.WINDOW;
+}
+
+function testWindowHost()
+{
+  checkHostType(Toolbox.HostType.WINDOW);
+
+  let sidebar = document.getElementById("devtools-toolbox-side-iframe");
+  ok(!sidebar, "toolbox sidebar iframe doesn't exist");
+
+  let win = Services.wm.getMostRecentWindow("devtools:toolbox");
+  ok(win, "toolbox separate window exists");
+
+  let iframe = win.document.getElementById("toolbox-iframe");
+  checkToolboxLoaded(iframe);
+
+  testToolSelect();
+}
+
+function testToolSelect()
+{
+  // make sure we can load a tool after switching hosts
+  toolbox.once("inspector-ready", testDestroy);
+  toolbox.selectTool("inspector");
+}
+
+function testDestroy()
+{
+  toolbox.once("destroyed", function() {
+    openToolbox(testRememberHost);
+  });
+
+  toolbox.destroy();
+}
+
+function testRememberHost()
+{
+  // last host was the window - make sure it's the same when re-opening
+  is(toolbox.hostType, Toolbox.HostType.WINDOW, "host remembered");
+
+  let win = Services.wm.getMostRecentWindow("devtools:toolbox");
+  ok(win, "toolbox separate window exists");
+
+  cleanup();
+}
+
+function checkHostType(hostType)
+{
+  is(toolbox.hostType, hostType, "host type is " + hostType);
+
+  let pref = Services.prefs.getCharPref("devtools.toolbox.host");
+  is(pref, hostType, "host pref is " + hostType);
+}
+
+function checkToolboxLoaded(iframe)
+{
+  let tabs = iframe.contentDocument.getElementById("toolbox-tabs");
+  ok(tabs, "toolbox UI has been loaded into iframe");
+}
+
+function cleanup()
+{
+  Services.prefs.setCharPref("devtools.toolbox.host", Toolbox.HostType.BOTTOM);
+
+  toolbox.destroy();
+  DevTools = Toolbox = toolbox = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_ready.js
@@ -0,0 +1,56 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let tempScope = {};
+Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+
+let toolbox;
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    openToolbox();
+  }, true);
+
+  content.location = "data:text/html,test for dynamically registering and unregistering tools";
+}
+
+function openToolbox()
+{
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  gDevTools.toggleToolboxForTarget(target);
+
+  toolbox = gDevTools.getToolboxForTarget(target);
+
+  ok(!toolbox.isReady, "toolbox isReady isn't set yet");
+
+  try {
+    toolbox.selectTool("webconsole");
+    ok(false, "Should throw when selectTool() called before toolbox is ready");
+  }
+  catch(error) {
+    is(error.message, "Can't select tool, wait for toolbox 'ready' event")
+  }
+
+  toolbox.once("ready", testReady);
+}
+
+function testReady()
+{
+  ok(toolbox.isReady, "toolbox isReady is set");
+  cleanup();
+}
+
+function cleanup()
+{
+  toolbox.destroy();
+  toolbox = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_select_event.js
@@ -0,0 +1,97 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let toolbox;
+
+function test() {
+  addTab("about:blank", function() {
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    toolbox = gDevTools.openToolbox(target, "bottom", "webconsole");
+    toolbox.once("ready", testSelect);
+  });
+}
+
+let called = {
+  inspector: false,
+  webconsole: false,
+  styleeditor: false,
+  //jsdebugger: false,
+}
+
+function testSelect() {
+  info("Toolbox fired a `ready` event");
+
+  toolbox.on("select", selectCB);
+
+  toolbox.selectTool("inspector");
+  toolbox.selectTool("webconsole");
+  toolbox.selectTool("styleeditor");
+  //toolbox.selectTool("jsdebugger");
+}
+
+function selectCB(event, id) {
+  called[id] = true;
+  info("toolbox-select event from " + id);
+
+  for (let tool in called) {
+    if (!called[tool]) {
+      return;
+    }
+  }
+
+  ok(true, "All the tools fired a 'select event'");
+  toolbox.off("select", selectCB);
+
+  reselect();
+}
+
+function reselect() {
+  for (let tool in called) {
+    called[tool] = false;
+  }
+
+  toolbox.once("inspector-selected", function() {
+    tidyUpIfAllCalled("inspector");
+  });
+
+  toolbox.once("webconsole-selected", function() {
+    tidyUpIfAllCalled("webconsole");
+  });
+
+  /*
+  toolbox.once("jsdebugger-selected", function() {
+    tidyUpIfAllCalled("jsdebugger");
+  });
+  */
+
+  toolbox.once("styleeditor-selected", function() {
+    tidyUpIfAllCalled("styleeditor");
+  });
+
+  toolbox.selectTool("inspector");
+  toolbox.selectTool("webconsole");
+  toolbox.selectTool("styleeditor");
+  //toolbox.selectTool("jsdebugger");
+}
+
+function tidyUpIfAllCalled(id) {
+  called[id] = true;
+  info("select event from " + id);
+
+  for (let tool in called) {
+    if (!called[tool]) {
+      return;
+    }
+  }
+
+  ok(true, "All the tools fired a {id}-selected event");
+  tidyUp();
+}
+
+function tidyUp() {
+  toolbox.destroy();
+  gBrowser.removeCurrentTab();
+
+  toolbox = null;
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_sidebar.js
@@ -0,0 +1,132 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test() {
+  const Cu = Components.utils;
+  let tempScope = {};
+  Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
+  Cu.import("resource:///modules/devtools/Target.jsm", tempScope);
+  Cu.import("resource:///modules/devtools/Sidebar.jsm", tempScope);
+  let {TargetFactory: TargetFactory, gDevTools: gDevTools, ToolSidebar: ToolSidebar} = tempScope;
+
+  const toolURL = "data:text/xml;charset=utf8,<?xml version='1.0'?>" +
+                  "<?xml-stylesheet href='chrome://browser/skin/devtools/common.css' type='text/css'?>" +
+                  "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'>" +
+                  "<hbox flex='1'><description flex='1'>foo</description><splitter class='devtools-side-splitter'/>" +
+                  "<tabbox flex='1' id='sidebar' class='devtools-sidebar-tabs'><tabs/><tabpanels flex='1'/></tabbox>" +
+                  "</hbox>" +
+                  "</window>";
+
+  const tab1URL = "data:text/html;charset=utf8,<title>1</title><p>1</p>";
+  const tab2URL = "data:text/html;charset=utf8,<title>2</title><p>2</p>";
+  const tab3URL = "data:text/html;charset=utf8,<title>3</title><p>3</p>";
+
+  let panelDoc;
+
+  let registeredTabs = {};
+  let readyTabs = {};
+
+  let toolDefinition = {
+    id: "fakeTool4242",
+    killswitch: "devtools.fakeTool4242.enabled",
+    url: toolURL,
+    label: "FAKE TOOL!!!",
+    isTargetSupported: function() true,
+    build: function(iframeWindow, toolbox) {
+      let panel = {
+        target: toolbox.target,
+        toolbox: toolbox,
+        isReady: true,
+        destroy: function(){},
+        panelDoc: iframeWindow.document,
+      }
+      return panel;
+    },
+  };
+
+  gDevTools.registerTool(toolDefinition);
+
+  addTab("about:blank", function(aBrowser, aTab) {
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let toolbox = gDevTools.openToolbox(target, "bottom", "fakeTool4242");
+    toolbox.once("fakeTool4242-ready", function(event, panel) {
+      ok(true, "Tool open");
+
+      let tabbox = panel.panelDoc.getElementById("sidebar");
+      panel.sidebar = new ToolSidebar(tabbox, panel, true);
+
+      panel.sidebar.on("new-tab-registered", function(event, id) {
+        registeredTabs[id] = true;
+      });
+
+      panel.sidebar.once("tab1-ready", function(event) {
+        readyTabs.tab1 = true;
+        if (readyTabs.tab1 && readyTabs.tab2 && readyTabs.tab3) {
+          allTabsReady(panel);
+        }
+      });
+
+      panel.sidebar.once("tab2-ready", function(event) {
+        readyTabs.tab2 = true;
+        if (readyTabs.tab1 && readyTabs.tab2 && readyTabs.tab3) {
+          allTabsReady(panel);
+        }
+      });
+
+      panel.sidebar.once("tab3-ready", function(event) {
+        readyTabs.tab3 = true;
+        if (readyTabs.tab1 && readyTabs.tab2 && readyTabs.tab3) {
+          allTabsReady(panel);
+        }
+      });
+
+      panel.sidebar.addTab("tab1", tab1URL, true);
+      panel.sidebar.addTab("tab2", tab2URL);
+      panel.sidebar.addTab("tab3", tab3URL);
+
+      panel.sidebar.show();
+    });
+  });
+
+  function allTabsReady(panel) {
+    ok(registeredTabs.tab1, "tab1 registered");
+    ok(registeredTabs.tab2, "tab2 registered");
+    ok(registeredTabs.tab3, "tab3 registered");
+    ok(readyTabs.tab1, "tab1 ready");
+    ok(readyTabs.tab2, "tab2 ready");
+    ok(readyTabs.tab3, "tab3 ready");
+
+    let tabs = panel.sidebar._tabbox.querySelectorAll("tab");
+    let panels = panel.sidebar._tabbox.querySelectorAll("tabpanel");
+    let label = 1;
+    for (let tab of tabs) {
+      is(tab.getAttribute("label"), label++, "Tab has the right title");
+    }
+    is(label, 4, "Found the right amount of tabs.");
+    is(panel.sidebar._tabbox.selectedPanel, panels[0], "First tab is selected");
+    ok(panel.sidebar.getCurrentTabID(), "tab1", "getCurrentTabID() is correct");
+
+    panel.sidebar.once("tab1-unselected", function() {
+      ok(true, "received 'unselected' event");
+      panel.sidebar.once("tab2-selected", function() {
+        ok(true, "received 'selected' event");
+        panel.sidebar.hide();
+        is(panel.sidebar._tabbox.getAttribute("hidden"), "true", "Sidebar hidden");
+        is(panel.sidebar.getWindowForTab("tab1").location.href, tab1URL, "Window is accessible");
+        finishUp(panel);
+      });
+    });
+
+    panel.sidebar.select("tab2");
+  }
+
+  function finishUp(panel) {
+    panel.sidebar.destroy();
+    gDevTools.unregisterTool(toolDefinition.id);
+
+    executeSoon(function() {
+      gBrowser.removeCurrentTab();
+      finish();
+    });
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_toolbox_tool_ready.js
@@ -0,0 +1,72 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let temp = [];
+Cu.import("resource:///modules/devtools/Target.jsm", temp);
+let TargetFactory = temp.TargetFactory;
+
+function test() {
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
+    openAllTools();
+  }, true);
+
+  function openAllTools() {
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+
+    let tools = gDevTools.getToolDefinitions();
+    let expectedCallbacksCount = tools.size;
+
+    let firstTool = null;
+    // we transform the map to a [id, eventHasBeenFiredYet] map
+    for (let [id] of tools) {
+      if (!firstTool)
+        firstTool = id;
+      tools.set(id, false);
+    }
+
+    let toolbox = gDevTools.openToolbox(target, undefined, firstTool);
+
+    // We add the event listeners
+    for (let [toolId] of tools) {
+      let id = toolId;
+      info("Registering listener for " + id);
+      tools.set(id, false);
+      toolbox.on(id + "-ready", function(event, panel) {
+        expectedCallbacksCount--;
+        info("Got event "  + event);
+        is(toolbox.getToolPanels().get(id), panel, "Got the right tool panel for " + id);
+        tools.set(id, true);
+        if (expectedCallbacksCount == 0) {
+          // "executeSoon" because we want to let a chance
+          // to falsy code to fire unexpected ready events.
+          executeSoon(theEnd);
+        }
+        if (expectedCallbacksCount < 0) {
+          ok(false, "we are receiving too many events");
+        }
+      });
+    }
+
+    toolbox.once("ready", function() {
+      // We open all the 
+      for (let [id] of tools) {
+        if (id != firstTool) {
+          toolbox.selectTool(id);
+        }
+      }
+    });
+
+    function theEnd() {
+      for (let [id, called] of tools) {
+        ok(called, "Tool " + id + " has fired its ready event");
+      }
+      toolbox.destroy();
+      gBrowser.removeCurrentTab();
+      finish();
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/head.js
@@ -0,0 +1,36 @@
+/* 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/. */
+
+let tempScope = {};
+Components.utils.import("resource:///modules/devtools/Target.jsm", tempScope);
+let TargetFactory = tempScope.TargetFactory;
+Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
+let console = tempScope.console;
+
+/**
+ * Open a new tab at a URL and call a callback on load
+ */
+function addTab(aURL, aCallback)
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  content.location = aURL;
+
+  let tab = gBrowser.selectedTab;
+  let browser = gBrowser.getBrowserForTab(tab);
+
+  function onTabLoad() {
+    browser.removeEventListener("load", onTabLoad, true);
+    aCallback(browser, tab, browser.contentDocument);
+  }
+
+  browser.addEventListener("load", onTabLoad, true);
+}
+
+registerCleanupFunction(function tearDown() {
+  while (gBrowser.tabs.length > 1) {
+    gBrowser.removeCurrentTab();
+  }
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox-window.xul
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE window [
+<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" >
+ %toolboxDTD;
+]>
+
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        id="devtools-toolbox-window"
+        title="&window.title;"
+        macanimationtype="document"
+        fullscreenbutton="true"
+        windowtype="devtools:toolbox"
+        width="700" height="320"
+        persist="screenX screenY width height sizemode">
+
+  <commandset id="toolbox-commandset">
+    <command id="toolbox-cmd-close" oncommand="window.close();"/>
+  </commandset>
+
+  <keyset id="toolbox-keyset">
+    <key id="toolbox-key-close"
+         key="&closeCmd.key;"
+         command="toolbox-cmd-close"
+         modifiers="accel"/>
+  </keyset>
+
+  <iframe id="toolbox-iframe" flex="1"></iframe>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox.css
@@ -0,0 +1,10 @@
+/* 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/. */
+
+.devtools-tab > .radio-check,
+.devtools-tab > .radio-check-box1,
+.devtools-tab > .radio-spacer-box {
+  display: none;
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/toolbox.xul
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/shared/common.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/framework/toolbox.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/devtools/toolbox.css" type="text/css"?>
+<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <notificationbox id="toolbox-notificationbox" flex="1">
+    <toolbar class="devtools-tabbar">
+      <hbox id="toolbox-controls">
+        <toolbarbutton id="toolbox-close" class="devtools-closebutton"></toolbarbutton>
+        <hbox id="toolbox-dock-buttons"/>
+      </hbox>
+      <radiogroup id="toolbox-tabs" orient="horizontal">
+      </radiogroup>
+      <hbox id="toolbox-buttons" flex="1" pack="end"/>
+    </toolbar>
+    <deck id="toolbox-deck" flex="1">
+    </deck>
+  </notificationbox>
+</window>
deleted file mode 100644
--- a/browser/devtools/highlighter/CmdInspect.jsm
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'inspect' command
- */
-gcli.addCommand({
-  name: "inspect",
-  description: gcli.lookup("inspectDesc"),
-  manual: gcli.lookup("inspectManual"),
-  params: [
-    {
-      name: "selector",
-      type: "node",
-      description: gcli.lookup("inspectNodeDesc"),
-      manual: gcli.lookup("inspectNodeManual")
-    }
-  ],
-  exec: function Command_inspect(args, context) {
-    let document = context.environment.chromeDocument;
-    document.defaultView.InspectorUI.openInspectorUI(args.selector);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/highlighter/Makefile.in
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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/.
-
-DEPTH		= @DEPTH@
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-EXTRA_JS_MODULES = \
-	highlighter.jsm \
-	$(NULL)
-
-EXTRA_PP_JS_MODULES = \
-	inspector.jsm \
-	$(NULL)
-
-TEST_DIRS += test
-
-include $(topsrcdir)/config/rules.mk
-
-libs::
-	$(NSINSTALL) $(srcdir)/CmdInspect.jsm $(FINAL_TARGET)/modules/devtools
deleted file mode 100644
--- a/browser/devtools/highlighter/highlighter.jsm
+++ /dev/null
@@ -1,905 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-this.EXPORTED_SYMBOLS = ["Highlighter"];
-
-const INSPECTOR_INVISIBLE_ELEMENTS = {
-  "head": true,
-  "base": true,
-  "basefont": true,
-  "isindex": true,
-  "link": true,
-  "meta": true,
-  "script": true,
-  "style": true,
-  "title": true,
-};
-
-const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
-  // add ":visited" and ":link" after bug 713106 is fixed
-
-/**
- * A highlighter mechanism.
- *
- * The highlighter is built dynamically into the browser element.
- * The caller is in charge of destroying the highlighter (ie, the highlighter
- * won't be destroyed if a new tab is selected for example).
- *
- * API:
- *
- *   // Constructor and destructor.
- *   // @param aWindow - browser.xul window.
- *   Highlighter(aWindow);
- *   void destroy();
- *
- *   // Highlight a node.
- *   // @param aNode - node to highlight
- *   // @param aScroll - scroll to ensure the node is visible
- *   void highlight(aNode, aScroll);
- *
- *   // Get the selected node.
- *   DOMNode getNode();
- *
- *   // Lock and unlock the select node.
- *   void lock();
- *   void unlock();
- *
- *   // Show and hide the highlighter
- *   void show();
- *   void hide();
- *   boolean isHidden();
- *
- *   // Redraw the highlighter if the visible portion of the node has changed.
- *   void invalidateSize(aScroll);
- *
- *   // Is a node highlightable.
- *   boolean isNodeHighlightable(aNode);
- *
- *   // Show/hide the outline and the infobar
- *   void showInfobar();
- *   void hideInfobar();
- *   void showOutline();
- *   void hideOutline();
- *
- *   // Add/Remove listeners
- *   // @param aEvent - event name
- *   // @param aListener - function callback
- *   void addListener(aEvent, aListener);
- *   void removeListener(aEvent, aListener);
- *
- * Events:
- *
- *   "closed" - Highlighter is closing
- *   "nodeselected" - A new node has been selected
- *   "highlighting" - Highlighter is highlighting
- *   "locked" - The selected node has been locked
- *   "unlocked" - The selected ndoe has been unlocked
- *   "pseudoclasstoggled" - A pseudo-class lock has changed on the selected node
- *
- * Structure:
- *  <stack id="highlighter-container">
- *    <box id="highlighter-outline-container">
- *      <box id="highlighter-outline" locked="true/false"/>
- *    </box>
- *    <box id="highlighter-controls">
- *      <box id="highlighter-nodeinfobar-container" position="top/bottom" locked="true/false">
- *        <box class="highlighter-nodeinfobar-arrow" id="highlighter-nodeinfobar-arrow-top"/>
- *        <hbox id="highlighter-nodeinfobar">
- *          <toolbarbutton id="highlighter-nodeinfobar-inspectbutton" class="highlighter-nodeinfobar-button"/>
- *          <hbox id="highlighter-nodeinfobar-text">tagname#id.class1.class2</hbox>
- *          <toolbarbutton id="highlighter-nodeinfobar-menu" class="highlighter-nodeinfobar-button">…</toolbarbutton>
- *        </hbox>
- *        <box class="highlighter-nodeinfobar-arrow" id="highlighter-nodeinfobar-arrow-bottom"/>
- *      </box>
- *    </box>
- *  </stack>
- *
- */
-
-
-/**
- * Constructor.
- *
- * @param object aWindow
- */
-this.Highlighter = function Highlighter(aWindow)
-{
-  this.chromeWin = aWindow;
-  this.tabbrowser = aWindow.gBrowser;
-  this.chromeDoc = aWindow.document;
-  this.browser = aWindow.gBrowser.selectedBrowser;
-  this.events = {};
-
-  this._init();
-}
-
-Highlighter.prototype = {
-  _init: function Highlighter__init()
-  {
-    let stack = this.browser.parentNode;
-    this.win = this.browser.contentWindow;
-    this._highlighting = false;
-
-    this.highlighterContainer = this.chromeDoc.createElement("stack");
-    this.highlighterContainer.id = "highlighter-container";
-
-    this.outline = this.chromeDoc.createElement("box");
-    this.outline.id = "highlighter-outline";
-
-    let outlineContainer = this.chromeDoc.createElement("box");
-    outlineContainer.appendChild(this.outline);
-    outlineContainer.id = "highlighter-outline-container";
-
-    // The controlsBox will host the different interactive
-    // elements of the highlighter (buttons, toolbars, ...).
-    let controlsBox = this.chromeDoc.createElement("box");
-    controlsBox.id = "highlighter-controls";
-    this.highlighterContainer.appendChild(outlineContainer);
-    this.highlighterContainer.appendChild(controlsBox);
-
-    // Insert the highlighter right after the browser
-    stack.insertBefore(this.highlighterContainer, stack.childNodes[1]);
-
-    this.buildInfobar(controlsBox);
-
-    this.transitionDisabler = null;
-    this.pageEventsMuter = null;
-
-    this.unlock();
-
-    this.hidden = true;
-    this.show();
-  },
-
-  /**
-   * Destroy the nodes. Remove listeners.
-   */
-  destroy: function Highlighter_destroy()
-  {
-    this.detachMouseListeners();
-    this.detachPageListeners();
-
-    this.chromeWin.clearTimeout(this.transitionDisabler);
-    this.chromeWin.clearTimeout(this.pageEventsMuter);
-    this.boundCloseEventHandler = null;
-    this._contentRect = null;
-    this._highlightRect = null;
-    this._highlighting = false;
-    this.outline = null;
-    this.node = null;
-    this.nodeInfo = null;
-    this.highlighterContainer.parentNode.removeChild(this.highlighterContainer);
-    this.highlighterContainer = null;
-    this.win = null
-    this.browser = null;
-    this.chromeDoc = null;
-    this.chromeWin = null;
-    this.tabbrowser = null;
-
-    this.emitEvent("closed");
-    this.removeAllListeners();
-  },
-
-  /**
-   * Show the outline, and select a node.
-   * If no node is specified, the previous selected node is highlighted if any.
-   * If no node was selected, the root element is selected.
-   *
-   * @param aNode [optional] - The node to be selected.
-   * @param aScroll [optional] boolean
-   *        Should we scroll to ensure that the selected node is visible.
-   */
-  highlight: function Highlighter_highlight(aNode, aScroll)
-  {
-    if (this.hidden)
-      this.show();
-
-    let oldNode = this.node;
-
-    if (!aNode) {
-      if (!this.node)
-        this.node = this.win.document.documentElement;
-    } else {
-      this.node = aNode;
-    }
-
-    if (oldNode !== this.node) {
-      this.updateInfobar();
-    }
-
-    this.invalidateSize(!!aScroll);
-
-    if (oldNode !== this.node) {
-      this.emitEvent("nodeselected");
-    }
-  },
-
-  /**
-   * Notify that a pseudo-class lock was toggled on the highlighted element
-   *
-   * @param aPseudo - The pseudo-class to toggle, e.g. ":hover".
-   */
-  pseudoClassLockToggled: function Highlighter_pseudoClassLockToggled(aPseudo)
-  {
-    this.emitEvent("pseudoclasstoggled", [aPseudo]);
-    this.updateInfobar();
-    this.moveInfobar();
-  },
-
-  /**
-   * Update the highlighter size and position.
-   */
-  invalidateSize: function Highlighter_invalidateSize(aScroll)
-  {
-    let rect = null;
-
-    if (this.node && this.isNodeHighlightable(this.node)) {
-
-      if (aScroll &&
-          this.node.scrollIntoView) { // XUL elements don't have such method
-        this.node.scrollIntoView();
-      }
-      let clientRect = this.node.getBoundingClientRect();
-      rect = LayoutHelpers.getDirtyRect(this.node);
-    }
-
-    this.highlightRectangle(rect);
-
-    this.moveInfobar();
-
-    if (this._highlighting) {
-      this.showOutline();
-      this.emitEvent("highlighting");
-    }
-  },
-
-  /**
-   * Returns the selected node.
-   *
-   * @returns node
-   */
-  getNode: function() {
-    return this.node;
-  },
-
-  /**
-   * Show the highlighter if it has been hidden.
-   */
-  show: function() {
-    if (!this.hidden) return;
-    this.showOutline();
-    this.showInfobar();
-    this.computeZoomFactor();
-    this.attachPageListeners();
-    this.invalidateSize();
-    this.hidden = false;
-  },
-
-  /**
-   * Hide the highlighter, the outline and the infobar.
-   */
-  hide: function() {
-    if (this.hidden) return;
-    this.hideOutline();
-    this.hideInfobar();
-    this.detachPageListeners();
-    this.hidden = true;
-  },
-
-  /**
-   * Is the highlighter visible?
-   *
-   * @return boolean
-   */
-  isHidden: function() {
-    return this.hidden;
-  },
-
-  /**
-   * Lock a node. Stops the inspection.
-   */
-  lock: function() {
-    if (this.locked === true) return;
-    this.outline.setAttribute("locked", "true");
-    this.nodeInfo.container.setAttribute("locked", "true");
-    this.detachMouseListeners();
-    this.locked = true;
-    this.emitEvent("locked");
-  },
-
-  /**
-   * Start inspecting.
-   * Unlock the current node (if any), and select any node being hovered.
-   */
-  unlock: function() {
-    if (this.locked === false) return;
-    this.outline.removeAttribute("locked");
-    this.nodeInfo.container.removeAttribute("locked");
-    this.attachMouseListeners();
-    this.locked = false;
-    this.showOutline();
-    this.emitEvent("unlocked");
-  },
-
-  /**
-   * Is the specified node highlightable?
-   *
-   * @param nsIDOMNode aNode
-   *        the DOM element in question
-   * @returns boolean
-   *          True if the node is highlightable or false otherwise.
-   */
-  isNodeHighlightable: function Highlighter_isNodeHighlightable(aNode)
-  {
-    if (!LayoutHelpers.isNodeConnected(aNode)) {
-      return false;
-    }
-    if (aNode.nodeType != aNode.ELEMENT_NODE) {
-      return false;
-    }
-    let nodeName = aNode.nodeName.toLowerCase();
-    return !INSPECTOR_INVISIBLE_ELEMENTS[nodeName];
-  },
-
-  /**
-   * Hide the infobar
-   */
-   hideInfobar: function Highlighter_hideInfobar() {
-     this.nodeInfo.container.setAttribute("force-transitions", "true");
-     this.nodeInfo.container.setAttribute("hidden", "true");
-   },
-
-  /**
-   * Show the infobar
-   */
-   showInfobar: function Highlighter_showInfobar() {
-     this.nodeInfo.container.removeAttribute("hidden");
-     this.moveInfobar();
-     this.nodeInfo.container.removeAttribute("force-transitions");
-   },
-
-  /**
-   * Hide the outline
-   */
-   hideOutline: function Highlighter_hideOutline() {
-     this.outline.setAttribute("hidden", "true");
-   },
-
-  /**
-   * Show the outline
-   */
-   showOutline: function Highlighter_showOutline() {
-     if (this._highlighting)
-       this.outline.removeAttribute("hidden");
-   },
-
-  /**
-   * Build the node Infobar.
-   *
-   * <box id="highlighter-nodeinfobar-container">
-   *   <box id="Highlighter-nodeinfobar-arrow-top"/>
-   *   <hbox id="highlighter-nodeinfobar">
-   *     <toolbarbutton class="highlighter-nodeinfobar-button" id="highlighter-nodeinfobar-inspectbutton"/>
-   *     <hbox id="highlighter-nodeinfobar-text">
-   *       <xhtml:span id="highlighter-nodeinfobar-tagname"/>
-   *       <xhtml:span id="highlighter-nodeinfobar-id"/>
-   *       <xhtml:span id="highlighter-nodeinfobar-classes"/>
-   *       <xhtml:span id="highlighter-nodeinfobar-pseudo-classes"/>
-   *     </hbox>
-   *     <toolbarbutton class="highlighter-nodeinfobar-button" id="highlighter-nodeinfobar-menu"/>
-   *   </hbox>
-   *   <box id="Highlighter-nodeinfobar-arrow-bottom"/>
-   * </box>
-   *
-   * @param nsIDOMElement aParent
-   *        The container of the infobar.
-   */
-  buildInfobar: function Highlighter_buildInfobar(aParent)
-  {
-    let container = this.chromeDoc.createElement("box");
-    container.id = "highlighter-nodeinfobar-container";
-    container.setAttribute("position", "top");
-    container.setAttribute("disabled", "true");
-
-    let nodeInfobar = this.chromeDoc.createElement("hbox");
-    nodeInfobar.id = "highlighter-nodeinfobar";
-
-    nodeInfobar.addEventListener("mousedown", function(aEvent) {
-      this.emitEvent("nodeselected");
-    }.bind(this), true);
-
-    let arrowBoxTop = this.chromeDoc.createElement("box");
-    arrowBoxTop.className = "highlighter-nodeinfobar-arrow";
-    arrowBoxTop.id = "highlighter-nodeinfobar-arrow-top";
-
-    let arrowBoxBottom = this.chromeDoc.createElement("box");
-    arrowBoxBottom.className = "highlighter-nodeinfobar-arrow";
-    arrowBoxBottom.id = "highlighter-nodeinfobar-arrow-bottom";
-
-    let tagNameLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
-    tagNameLabel.id = "highlighter-nodeinfobar-tagname";
-
-    let idLabel = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
-    idLabel.id = "highlighter-nodeinfobar-id";
-
-    let classesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
-    classesBox.id = "highlighter-nodeinfobar-classes";
-
-    let pseudoClassesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
-    pseudoClassesBox.id = "highlighter-nodeinfobar-pseudo-classes";
-
-    // Add some content to force a better boundingClientRect down below.
-    pseudoClassesBox.textContent = "&nbsp;";
-
-    // Create buttons
-
-    let inspect = this.chromeDoc.createElement("toolbarbutton");
-    inspect.id = "highlighter-nodeinfobar-inspectbutton";
-    inspect.className = "highlighter-nodeinfobar-button"
-    let toolbarInspectButton =
-      this.chromeDoc.getElementById("inspector-inspect-toolbutton");
-    inspect.setAttribute("tooltiptext",
-                         toolbarInspectButton.getAttribute("tooltiptext"));
-    inspect.setAttribute("command", "Inspector:Inspect");
-
-    let nodemenu = this.chromeDoc.createElement("toolbarbutton");
-    nodemenu.setAttribute("type", "menu");
-    nodemenu.id = "highlighter-nodeinfobar-menu";
-    nodemenu.className = "highlighter-nodeinfobar-button"
-    nodemenu.setAttribute("tooltiptext",
-                          this.strings.GetStringFromName("nodeMenu.tooltiptext"));
-
-    let menu = this.chromeDoc.getElementById("inspector-node-popup");
-    menu = menu.cloneNode(true);
-    menu.id = "highlighter-node-menu";
-
-    let separator = this.chromeDoc.createElement("menuseparator");
-    menu.appendChild(separator);
-
-    menu.addEventListener("popupshowing", function() {
-      let items = menu.getElementsByClassName("highlighter-pseudo-class-menuitem");
-      let i = items.length;
-      while (i--) {
-        menu.removeChild(items[i]);
-      }
-
-      let fragment = this.buildPseudoClassMenu();
-      menu.appendChild(fragment);
-    }.bind(this), true);
-
-    nodemenu.appendChild(menu);
-
-    // <hbox id="highlighter-nodeinfobar-text"/>
-    let texthbox = this.chromeDoc.createElement("hbox");
-    texthbox.id = "highlighter-nodeinfobar-text";
-    texthbox.setAttribute("align", "center");
-    texthbox.setAttribute("flex", "1");
-
-    texthbox.appendChild(tagNameLabel);
-    texthbox.appendChild(idLabel);
-    texthbox.appendChild(classesBox);
-    texthbox.appendChild(pseudoClassesBox);
-
-    nodeInfobar.appendChild(inspect);
-    nodeInfobar.appendChild(texthbox);
-    nodeInfobar.appendChild(nodemenu);
-
-    container.appendChild(arrowBoxTop);
-    container.appendChild(nodeInfobar);
-    container.appendChild(arrowBoxBottom);
-
-    aParent.appendChild(container);
-
-    let barHeight = container.getBoundingClientRect().height;
-
-    this.nodeInfo = {
-      tagNameLabel: tagNameLabel,
-      idLabel: idLabel,
-      classesBox: classesBox,
-      pseudoClassesBox: pseudoClassesBox,
-      container: container,
-      barHeight: barHeight,
-    };
-  },
-
-  /**
-   * Create the menuitems for toggling the selection's pseudo-class state
-   *
-   * @returns DocumentFragment. The menuitems for toggling pseudo-classes.
-   */
-  buildPseudoClassMenu: function IUI_buildPseudoClassesMenu()
-  {
-    let fragment = this.chromeDoc.createDocumentFragment();
-    for (let i = 0; i < PSEUDO_CLASSES.length; i++) {
-      let pseudo = PSEUDO_CLASSES[i];
-      let item = this.chromeDoc.createElement("menuitem");
-      item.id = "highlighter-pseudo-class-menuitem-" + pseudo;
-      item.setAttribute("type", "checkbox");
-      item.setAttribute("label", pseudo);
-      item.className = "highlighter-pseudo-class-menuitem";
-      item.setAttribute("checked", DOMUtils.hasPseudoClassLock(this.node,
-                        pseudo));
-      item.addEventListener("command",
-                            this.pseudoClassLockToggled.bind(this, pseudo), false);
-      fragment.appendChild(item);
-    }
-    return fragment;
-  },
-
-  /**
-   * Highlight a rectangular region.
-   *
-   * @param object aRect
-   *        The rectangle region to highlight.
-   * @returns boolean
-   *          True if the rectangle was highlighted, false otherwise.
-   */
-  highlightRectangle: function Highlighter_highlightRectangle(aRect)
-  {
-    if (!aRect) {
-      this.unhighlight();
-      return;
-    }
-
-    let oldRect = this._contentRect;
-
-    if (oldRect && aRect.top == oldRect.top && aRect.left == oldRect.left &&
-        aRect.width == oldRect.width && aRect.height == oldRect.height) {
-      return; // same rectangle
-    }
-
-    let aRectScaled = LayoutHelpers.getZoomedRect(this.win, aRect);
-
-    if (aRectScaled.left >= 0 && aRectScaled.top >= 0 &&
-        aRectScaled.width > 0 && aRectScaled.height > 0) {
-
-      this.showOutline();
-
-      // The bottom div and the right div are flexibles (flex=1).
-      // We don't need to resize them.
-      let top = "top:" + aRectScaled.top + "px;";
-      let left = "left:" + aRectScaled.left + "px;";
-      let width = "width:" + aRectScaled.width + "px;";
-      let height = "height:" + aRectScaled.height + "px;";
-      this.outline.setAttribute("style", top + left + width + height);
-
-      this._highlighting = true;
-    } else {
-      this.unhighlight();
-    }
-
-    this._contentRect = aRect; // save orig (non-scaled) rect
-    this._highlightRect = aRectScaled; // and save the scaled rect.
-
-    return;
-  },
-
-  /**
-   * Clear the highlighter surface.
-   */
-  unhighlight: function Highlighter_unhighlight()
-  {
-    this._highlighting = false;
-    this.hideOutline();
-  },
-
-  /**
-   * Update node information (tagName#id.class)
-   */
-  updateInfobar: function Highlighter_updateInfobar()
-  {
-    // Tag name
-    this.nodeInfo.tagNameLabel.textContent = this.node.tagName;
-
-    // ID
-    this.nodeInfo.idLabel.textContent = this.node.id ? "#" + this.node.id : "";
-
-    // Classes
-    let classes = this.nodeInfo.classesBox;
-
-    classes.textContent = this.node.classList.length ?
-                            "." + Array.join(this.node.classList, ".") : "";
-
-    // Pseudo-classes
-    let pseudos = PSEUDO_CLASSES.filter(function(pseudo) {
-      return DOMUtils.hasPseudoClassLock(this.node, pseudo);
-    }, this);
-
-    let pseudoBox = this.nodeInfo.pseudoClassesBox;
-    pseudoBox.textContent = pseudos.join("");
-  },
-
-  /**
-   * Move the Infobar to the right place in the highlighter.
-   */
-  moveInfobar: function Highlighter_moveInfobar()
-  {
-    if (this._highlightRect) {
-      let winHeight = this.win.innerHeight * this.zoom;
-      let winWidth = this.win.innerWidth * this.zoom;
-
-      let rect = {top: this._highlightRect.top,
-                  left: this._highlightRect.left,
-                  width: this._highlightRect.width,
-                  height: this._highlightRect.height};
-
-      rect.top = Math.max(rect.top, 0);
-      rect.left = Math.max(rect.left, 0);
-      rect.width = Math.max(rect.width, 0);
-      rect.height = Math.max(rect.height, 0);
-
-      rect.top = Math.min(rect.top, winHeight);
-      rect.left = Math.min(rect.left, winWidth);
-
-      this.nodeInfo.container.removeAttribute("disabled");
-      // Can the bar be above the node?
-      if (rect.top < this.nodeInfo.barHeight) {
-        // No. Can we move the toolbar under the node?
-        if (rect.top + rect.height +
-            this.nodeInfo.barHeight > winHeight) {
-          // No. Let's move it inside.
-          this.nodeInfo.container.style.top = rect.top + "px";
-          this.nodeInfo.container.setAttribute("position", "overlap");
-        } else {
-          // Yes. Let's move it under the node.
-          this.nodeInfo.container.style.top = rect.top + rect.height + "px";
-          this.nodeInfo.container.setAttribute("position", "bottom");
-        }
-      } else {
-        // Yes. Let's move it on top of the node.
-        this.nodeInfo.container.style.top =
-          rect.top - this.nodeInfo.barHeight + "px";
-        this.nodeInfo.container.setAttribute("position", "top");
-      }
-
-      let barWidth = this.nodeInfo.container.getBoundingClientRect().width;
-      let left = rect.left + rect.width / 2 - barWidth / 2;
-
-      // Make sure the whole infobar is visible
-      if (left < 0) {
-        left = 0;
-        this.nodeInfo.container.setAttribute("hide-arrow", "true");
-      } else {
-        if (left + barWidth > winWidth) {
-          left = winWidth - barWidth;
-          this.nodeInfo.container.setAttribute("hide-arrow", "true");
-        } else {
-          this.nodeInfo.container.removeAttribute("hide-arrow");
-        }
-      }
-      this.nodeInfo.container.style.left = left + "px";
-    } else {
-      this.nodeInfo.container.style.left = "0";
-      this.nodeInfo.container.style.top = "0";
-      this.nodeInfo.container.setAttribute("position", "top");
-      this.nodeInfo.container.setAttribute("hide-arrow", "true");
-    }
-  },
-
-  /**
-   * Store page zoom factor.
-   */
-  computeZoomFactor: function Highlighter_computeZoomFactor() {
-    this.zoom =
-      this.win.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIDOMWindowUtils)
-      .fullZoom;
-  },
-
-  /////////////////////////////////////////////////////////////////////////
-  //// Event Emitter Mechanism
-
-  addListener: function Highlighter_addListener(aEvent, aListener)
-  {
-    if (!(aEvent in this.events))
-      this.events[aEvent] = [];
-    this.events[aEvent].push(aListener);
-  },
-
-  removeListener: function Highlighter_removeListener(aEvent, aListener)
-  {
-    if (!(aEvent in this.events))
-      return;
-    let idx = this.events[aEvent].indexOf(aListener);
-    if (idx > -1)
-      this.events[aEvent].splice(idx, 1);
-  },
-
-  emitEvent: function Highlighter_emitEvent(aEvent, aArgv)
-  {
-    if (!(aEvent in this.events))
-      return;
-
-    let listeners = this.events[aEvent];
-    let highlighter = this;
-    listeners.forEach(function(aListener) {
-      try {
-        aListener.apply(highlighter, aArgv);
-      } catch(e) {}
-    });
-  },
-
-  removeAllListeners: function Highlighter_removeAllIsteners()
-  {
-    for (let event in this.events) {
-      delete this.events[event];
-    }
-  },
-
-  /////////////////////////////////////////////////////////////////////////
-  //// Event Handling
-
-  attachMouseListeners: function Highlighter_attachMouseListeners()
-  {
-    this.browser.addEventListener("mousemove", this, true);
-    this.browser.addEventListener("click", this, true);
-    this.browser.addEventListener("dblclick", this, true);
-    this.browser.addEventListener("mousedown", this, true);
-    this.browser.addEventListener("mouseup", this, true);
-  },
-
-  detachMouseListeners: function Highlighter_detachMouseListeners()
-  {
-    this.browser.removeEventListener("mousemove", this, true);
-    this.browser.removeEventListener("click", this, true);
-    this.browser.removeEventListener("dblclick", this, true);
-    this.browser.removeEventListener("mousedown", this, true);
-    this.browser.removeEventListener("mouseup", this, true);
-  },
-
-  attachPageListeners: function Highlighter_attachPageListeners()
-  {
-    this.browser.addEventListener("resize", this, true);
-    this.browser.addEventListener("scroll", this, true);
-    this.browser.addEventListener("MozAfterPaint", this, true);
-  },
-
-  detachPageListeners: function Highlighter_detachPageListeners()
-  {
-    this.browser.removeEventListener("resize", this, true);
-    this.browser.removeEventListener("scroll", this, true);
-    this.browser.removeEventListener("MozAfterPaint", this, true);
-  },
-
-  /**
-   * Generic event handler.
-   *
-   * @param nsIDOMEvent aEvent
-   *        The DOM event object.
-   */
-  handleEvent: function Highlighter_handleEvent(aEvent)
-  {
-    switch (aEvent.type) {
-      case "click":
-        this.handleClick(aEvent);
-        break;
-      case "mousemove":
-        this.brieflyIgnorePageEvents();
-        this.handleMouseMove(aEvent);
-        break;
-      case "resize":
-        this.computeZoomFactor();
-        break;
-      case "MozAfterPaint":
-      case "scroll":
-        this.brieflyDisableTransitions();
-        this.invalidateSize();
-        break;
-      case "dblclick":
-      case "mousedown":
-      case "mouseup":
-        aEvent.stopPropagation();
-        aEvent.preventDefault();
-        break;
-    }
-  },
-
-  /**
-   * Disable the CSS transitions for a short time to avoid laggy animations
-   * during scrolling or resizing.
-   */
-  brieflyDisableTransitions: function Highlighter_brieflyDisableTransitions()
-  {
-    if (this.transitionDisabler) {
-      this.chromeWin.clearTimeout(this.transitionDisabler);
-    } else {
-      this.outline.setAttribute("disable-transitions", "true");
-      this.nodeInfo.container.setAttribute("disable-transitions", "true");
-    }
-    this.transitionDisabler =
-      this.chromeWin.setTimeout(function() {
-        this.outline.removeAttribute("disable-transitions");
-        this.nodeInfo.container.removeAttribute("disable-transitions");
-        this.transitionDisabler = null;
-      }.bind(this), 500);
-  },
-
-  /**
-   * Don't listen to page events while inspecting with the mouse.
-   */
-  brieflyIgnorePageEvents: function Highlighter_brieflyIgnorePageEvents()
-  {
-    // The goal is to keep smooth animations while inspecting.
-    // CSS Transitions might be interrupted because of a MozAfterPaint
-    // event that would triger an invalidateSize() call.
-    // So we don't listen to events that would trigger an invalidateSize()
-    // call.
-    //
-    // Side effect, zoom levels are not updated during this short period.
-    // It's very unlikely this would happen, but just in case, we call
-    // computeZoomFactor() when reattaching the events.
-    if (this.pageEventsMuter) {
-      this.chromeWin.clearTimeout(this.pageEventsMuter);
-    } else {
-      this.detachPageListeners();
-    }
-    this.pageEventsMuter =
-      this.chromeWin.setTimeout(function() {
-        this.attachPageListeners();
-        // Just in case the zoom level changed while ignoring the paint events
-        this.computeZoomFactor();
-        this.pageEventsMuter = null;
-      }.bind(this), 500);
-  },
-
-  /**
-   * Handle clicks.
-   *
-   * @param nsIDOMEvent aEvent
-   *        The DOM event.
-   */
-  handleClick: function Highlighter_handleClick(aEvent)
-  {
-    // Stop inspection when the user clicks on a node.
-    if (aEvent.button == 0) {
-      let win = aEvent.target.ownerDocument.defaultView;
-      this.lock();
-      win.focus();
-      aEvent.preventDefault();
-      aEvent.stopPropagation();
-    }
-  },
-
-  /**
-   * Handle mousemoves in panel.
-   *
-   * @param nsiDOMEvent aEvent
-   *        The MouseEvent triggering the method.
-   */
-  handleMouseMove: function Highlighter_handleMouseMove(aEvent)
-  {
-    let doc = aEvent.target.ownerDocument;
-
-    // This should never happen, but just in case, we don't let the
-    // highlighter highlight browser nodes.
-    if (doc && doc != this.chromeDoc) {
-      let element = LayoutHelpers.getElementFromPoint(aEvent.target.ownerDocument,
-        aEvent.clientX, aEvent.clientY);
-      if (element && element != this.node) {
-        this.highlight(element);
-      }
-    }
-  },
-};
-
-///////////////////////////////////////////////////////////////////////////
-
-XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
-  return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils)
-});
-
-XPCOMUtils.defineLazyGetter(Highlighter.prototype, "strings", function () {
-    return Services.strings.createBundle(
-            "chrome://browser/locale/devtools/inspector.properties");
-});
deleted file mode 100644
--- a/browser/devtools/highlighter/inspector.jsm
+++ /dev/null
@@ -1,2414 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const Cc = Components.classes;
-const Cu = Components.utils;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-
-this.EXPORTED_SYMBOLS = ["InspectorUI"];
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/devtools/MarkupView.jsm");
-Cu.import("resource:///modules/highlighter.jsm");
-Cu.import("resource:///modules/devtools/LayoutView.jsm");
-Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
-Cu.import("resource:///modules/devtools/EventEmitter.jsm");
-Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
-
-// Inspector notifications dispatched through the nsIObserverService.
-const INSPECTOR_NOTIFICATIONS = {
-  // Fires once the Inspector completes the initialization and opens up on
-  // screen.
-  OPENED: "inspector-opened",
-
-  // Fires once the Inspector is closed.
-  CLOSED: "inspector-closed",
-
-  // Fires once the Inspector is destroyed. Not fired on tab switch.
-  DESTROYED: "inspector-destroyed",
-
-  // Fires when the Inspector is reopened after tab-switch.
-  STATE_RESTORED: "inspector-state-restored",
-
-  // Fires when the Tree Panel is opened and initialized.
-  TREEPANELREADY: "inspector-treepanel-ready",
-
-  // Event notifications for the attribute-value editor
-  EDITOR_OPENED: "inspector-editor-opened",
-  EDITOR_CLOSED: "inspector-editor-closed",
-  EDITOR_SAVED: "inspector-editor-saved",
-};
-
-const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
-
-// Timer, in milliseconds, between change events fired by
-// things like resize events.
-const LAYOUT_CHANGE_TIMER = 250;
-
-/**
- * Represents an open instance of the Inspector for a tab.
- * This is the object handed out to sidebars and other API consumers.
- *
- * Right now it's a thin layer over InspectorUI, but we will
- * start moving per-tab state into this object soon, eventually
- * replacing the per-winID InspectorStore objects.
- *
- * The lifetime of this object is also not yet correct.  This object
- * is currently destroyed when the inspector is torn down, either by user
- * closing the inspector or by user switching the tab.  This should
- * only be destroyed when user closes the inspector.
- */
-function Inspector(aIUI)
-{
-  this._IUI = aIUI;
-  this._winID = aIUI.winID;
-  this._browser = aIUI.browser;
-  this._eventEmitter = new EventEmitter();
-
-  this._browser.addEventListener("resize", this, true);
-
-  this._markupButton = this._IUI.chromeDoc.getElementById("inspector-treepanel-toolbutton");
-
-  if (Services.prefs.getBoolPref("devtools.inspector.htmlPanelOpen")) {
-    this.openMarkup();
-  } else {
-    this.closeMarkup();
-  }
-
-}
-
-Inspector.prototype = {
-  /**
-   * True if the highlighter is locked on a node.
-   */
-  get locked() {
-    return !this._IUI.inspecting;
-  },
-
-  /**
-   * The currently selected node in the highlighter.
-   */
-  get selection() {
-    return this._IUI.selection;
-  },
-
-  /**
-   * Indicate that a tool has modified the state of the page.  Used to
-   * decide whether to show the "are you sure you want to navigate"
-   * notification.
-   */
-  markDirty: function Inspector_markDirty()
-  {
-    this._IUI.isDirty = true;
-  },
-
-  /**
-   * The chrome window the inspector lives in.
-   */
-  get chromeWindow() {
-    return this._IUI.chromeWin;
-  },
-
-  /**
-   * Notify the inspector that the current selection has changed.
-   *
-   * @param string aContext
-   *        An string that will be passed to the change event.  Allows
-   *        a tool to recognize when it sent a change notification itself
-   *        to avoid unnecessary refresh.
-   */
-  change: function Inspector_change(aContext)
-  {
-    this._cancelLayoutChange();
-    this._IUI.nodeChanged(aContext);
-  },
-
-  /**
-   * Returns true if a given sidebar panel is currently visible.
-   * @param string aPanelName
-   *        The panel name as registered with registerSidebar
-   */
-  isPanelVisible: function Inspector_isPanelVisible(aPanelName)
-  {
-    return this._IUI.sidebar.visible &&
-           this._IUI.sidebar.activePanel === aPanelName;
-  },
-
-  /**
-   * Called by the InspectorUI when the inspector is being destroyed.
-   */
-  _destroy: function Inspector__destroy()
-  {
-    this._cancelLayoutChange();
-    this._destroyMarkup();
-    this._browser.removeEventListener("resize", this, true);
-    delete this._IUI;
-    delete this._eventEmitter;
-  },
-
-  /**
-   * Event handler for DOM events.
-   *
-   * @param DOMEvent aEvent
-   */
-  handleEvent: function Inspector_handleEvent(aEvent)
-  {
-    switch(aEvent.type) {
-      case "resize":
-        this._scheduleLayoutChange();
-    }
-  },
-
-  /**
-   * Schedule a low-priority change event for things like paint
-   * and resize.
-   */
-  _scheduleLayoutChange: function Inspector_scheduleLayoutChange()
-  {
-    if (this._timer) {
-      return null;
-    }
-    this._timer = this._IUI.win.setTimeout(function() {
-      this.change("layout");
-    }.bind(this), LAYOUT_CHANGE_TIMER);
-  },
-
-  /**
-   * Cancel a pending low-priority change event if any is
-   * scheduled.
-   */
-  _cancelLayoutChange: function Inspector_cancelLayoutChange()
-  {
-    if (this._timer) {
-      this._IUI.win.clearTimeout(this._timer);
-      delete this._timer;
-    }
-  },
-
-  toggleMarkup: function Inspector_toggleMarkup()
-  {
-    if (this._markupFrame) {
-      this.closeMarkup();
-      Services.prefs.setBoolPref("devtools.inspector.htmlPanelOpen", false);
-    } else {
-      this.openMarkup(true);
-      Services.prefs.setBoolPref("devtools.inspector.htmlPanelOpen", true);
-    }
-  },
-
-  /**
-   * XXX: The sidebar has an object that exists and is manipulated
-   * separately from its actual loading.  So the public api for
-   * the sidebar looks like:
-   *
-   * if (inspector.sidebar.visible) { inspector.sidebar.close() }
-   *
-   * whereas the markup API looks more like
-   *
-   * if (inspector.markupOpen) { inspector.closeMarkup() }
-   *
-   * Maybe we should add an InspectorMarkup object that presents
-   * the public api for the markup panel?
-   */
-  get markupOpen() {
-    return this._markupOpen;
-  },
-
-  openMarkup: function Inspector_openMarkup(aFocus)
-  {
-    this._markupButton.setAttribute("checked", "true");
-    this._markupOpen = true;
-    if (!this._markupFrame) {
-      this._initMarkup(aFocus);
-    }
-  },
-
-  closeMarkup: function Inspector_closeMarkup()
-  {
-    this._markupButton.removeAttribute("checked");
-    this._markupOpen = false;
-    this._destroyMarkup();
-  },
-
-  _initMarkup: function Inspector_initMarkupPane(aFocus)
-  {
-    let doc = this._IUI.chromeDoc;
-
-    this._markupBox = doc.createElement("vbox");
-    try {
-      this._markupBox.height =
-        Services.prefs.getIntPref("devtools.inspector.htmlHeight");
-    } catch(e) {
-      this._markupBox.height = 112;
-    }
-    this._markupBox.minHeight = 64;
-
-    this._markupSplitter = doc.createElement("splitter");
-    this._markupSplitter.className = "devtools-horizontal-splitter";
-
-    let container = doc.getElementById("appcontent");
-    container.appendChild(this._markupSplitter);
-    container.appendChild(this._markupBox);
-
-    // create tool iframe
-    this._markupFrame = doc.createElement("iframe");
-    this._markupFrame.setAttribute("flex", "1");
-    this._markupFrame.setAttribute("tooltip", "aHTMLTooltip");
-    this._markupFrame.setAttribute("context", "inspector-node-popup");
-
-    // This is needed to enable tooltips inside the iframe document.
-    this._boundMarkupFrameLoad = function Inspector_initMarkupPanel_onload() {
-      if (aFocus) {
-        this._markupFrame.contentWindow.focus();
-      }
-      this._onMarkupFrameLoad();
-    }.bind(this);
-    this._markupFrame.addEventListener("load", this._boundMarkupFrameLoad, true);
-
-    this._markupSplitter.setAttribute("hidden", true);
-    this._markupBox.setAttribute("hidden", true);
-    this._markupBox.appendChild(this._markupFrame);
-    this._markupFrame.setAttribute("src", "chrome://browser/content/devtools/markup-view.xhtml");
-  },
-
-  _onMarkupFrameLoad: function Inspector__onMarkupFrameLoad()
-  {
-    this._markupFrame.removeEventListener("load", this._boundMarkupFrameLoad, true);
-    delete this._boundMarkupFrameLoad;
-
-    this._markupSplitter.removeAttribute("hidden");
-    this._markupBox.removeAttribute("hidden");
-
-    this.markup = new MarkupView(this, this._markupFrame);
-    this.emit("markuploaded");
-  },
-
-  _destroyMarkup: function Inspector__destroyMarkup()
-  {
-    if (this._boundMarkupFrameLoad) {
-      this._markupFrame.removeEventListener("load", this._boundMarkupFrameLoad, true);
-      delete this._boundMarkupFrameLoad;
-    }
-
-    if (this.markup) {
-      this.markup.destroy();
-      delete this.markup;
-    }
-
-    if (this._markupFrame) {
-      delete this._markupFrame;
-    }
-
-    if (this._markupBox) {
-      Services.prefs.setIntPref("devtools.inspector.htmlHeight", this._markupBox.height);
-      this._markupBox.parentNode.removeChild(this._markupBox);
-      delete this._markupBox;
-    }
-
-    if (this._markupSplitter) {
-      this._markupSplitter.parentNode.removeChild(this._markupSplitter);
-      delete this._markupSplitter;
-    }
-  },
-
-  /**
-   * Called by InspectorUI after a tab switch, when the
-   * inspector is no longer the active tab.
-   */
-  _freeze: function Inspector__freeze()
-  {
-    if (this._markupBox) {
-      this._markupSplitter.setAttribute("hidden", true);
-      this._markupBox.setAttribute("hidden", true);
-    }
-    this._cancelLayoutChange();
-    this._browser.removeEventListener("resize", this, true);
-    this._frozen = true;
-  },
-
-  /**
-   * Called by InspectorUI after a tab switch when the
-   * inspector is back to being the active tab.
-   */
-  _thaw: function Inspector__thaw()
-  {
-    if (!this._frozen) {
-      return;
-    }
-
-    if (this._markupOpen && !this._boundMarkupFrameLoad) {
-      this._markupSplitter.removeAttribute("hidden");
-      this._markupBox.removeAttribute("hidden");
-    }
-    this._browser.addEventListener("resize", this, true);
-    delete this._frozen;
-  },
-
-  /// Forward the events related calls to the event emitter.
-
-  /**
-   * Connect a listener to this object.
-   *
-   * @param string aEvent
-   *        The event name to which we're connecting.
-   * @param function aListener
-   *        Called when the event is fired.
-   */
-  on: function Inspector_on(aEvent, aListener)
-  {
-    this._eventEmitter.on(aEvent, aListener);
-  },
-
-  /**
-   * Listen for the next time an event is fired.
-   *
-   * @param string aEvent
-   *        The event name to which we're connecting.
-   * @param function aListener
-   *        Called when the event is fired.  Will be called at most one time.
-   */
-  once: function Inspector_once(aEvent, aListener)
-  {
-    this._eventEmitter.once(aEvent, aListener);
-  },
-
-  /**
-   * Remove a previously-registered event listener.  Works for events
-   * registered with either on or once.
-   *
-   * @param string aEvent
-   *        The event name whose listener we're disconnecting.
-   * @param function aListener
-   *        The listener to remove.
-   */
-  off: function Inspector_removeListener(aEvent, aListener)
-  {
-    this._eventEmitter.off(aEvent, aListener);
-  },
-
-  /**
-   * Emit an event on the inspector.  All arguments to this method will
-   * be sent to listner functions.
-   */
-  emit: function Inspector_emit()
-  {
-    this._eventEmitter.emit.apply(this._eventEmitter, arguments);
-  }
-}
-
-///////////////////////////////////////////////////////////////////////////
-//// InspectorUI
-
-/**
- * Main controller class for the Inspector.
- *
- * @constructor
- * @param nsIDOMWindow aWindow
- *        The chrome window for which the Inspector instance is created.
- */
-this.InspectorUI = function InspectorUI(aWindow)
-{
-  // Let style inspector tools register themselves.
-  let tmp = {};
-  Cu.import("resource:///modules/devtools/StyleInspector.jsm", tmp);
-
-  this.chromeWin = aWindow;
-  this.chromeDoc = aWindow.document;
-  this.tabbrowser = aWindow.gBrowser;
-  this.tools = {};
-  this.toolEvents = {};
-  this.store = new InspectorStore();
-  this.INSPECTOR_NOTIFICATIONS = INSPECTOR_NOTIFICATIONS;
-  this.buildButtonsTooltip();
-}
-
-InspectorUI.prototype = {
-  browser: null,
-  tools: null,
-  toolEvents: null,
-  inspecting: false,
-  ruleViewEnabled: true,
-  isDirty: false,
-  store: null,
-
-  _currentInspector: null,
-  _sidebar: null,
-
-  /**
-   * The Inspector object for the current tab.
-   */
-  get currentInspector() this._currentInspector,
-
-  /**
-   * The InspectorStyleSidebar for the current tab.
-   */
-  get sidebar() this._sidebar,
-
-  /**
-   * Toggle the inspector interface elements on or off.
-   *
-   * @param aEvent
-   *        The event that requested the UI change. Toolbar button or menu.
-   */
-  toggleInspectorUI: function IUI_toggleInspectorUI(aEvent)
-  {
-    if (this.isInspectorOpen) {
-      this.closeInspectorUI();
-    } else {
-      this.openInspectorUI();
-    }
-  },
-
-  /**
-   * Add a tooltip to the Inspect and Markup buttons.
-   * The tooltips include the related keyboard shortcut.
-   */
-  buildButtonsTooltip: function IUI_buildButtonsTooltip()
-  {
-    let keysbundle = Services.strings.createBundle("chrome://global-platform/locale/platformKeys.properties");
-    let separator = keysbundle.GetStringFromName("MODIFIER_SEPARATOR");
-
-    let button, tooltip;
-
-    // Inspect Button - the shortcut string is built from the <key> element
-
-    let key = this.chromeDoc.getElementById("key_inspect");
-
-    if (key) {
-      let modifiersAttr = key.getAttribute("modifiers");
-
-      let combo = [];
-
-      if (modifiersAttr.match("accel"))
-#ifdef XP_MACOSX
-        combo.push(keysbundle.GetStringFromName("VK_META"));
-#else
-        combo.push(keysbundle.GetStringFromName("VK_CONTROL"));
-#endif
-      if (modifiersAttr.match("shift"))
-        combo.push(keysbundle.GetStringFromName("VK_SHIFT"));
-      if (modifiersAttr.match("alt"))
-        combo.push(keysbundle.GetStringFromName("VK_ALT"));
-      if (modifiersAttr.match("ctrl"))
-        combo.push(keysbundle.GetStringFromName("VK_CONTROL"));
-      if (modifiersAttr.match("meta"))
-        combo.push(keysbundle.GetStringFromName("VK_META"));
-
-      combo.push(key.getAttribute("key"));
-
-      tooltip = this.strings.formatStringFromName("inspectButtonWithShortcutKey.tooltip",
-        [combo.join(separator)], 1);
-    } else {
-      tooltip = this.strings.GetStringFromName("inspectButton.tooltip");
-    }
-
-    button = this.chromeDoc.getElementById("inspector-inspect-toolbutton");
-    button.setAttribute("tooltiptext", tooltip);
-
-    // Markup Button - the shortcut string is built from the accesskey attribute
-
-    button = this.chromeDoc.getElementById("inspector-treepanel-toolbutton");
-#ifdef XP_MACOSX
-    // On Mac, no accesskey
-    tooltip = this.strings.GetStringFromName("markupButton.tooltip");
-#else
-    let altString = keysbundle.GetStringFromName("VK_ALT");
-    let accesskey = button.getAttribute("accesskey");
-    let shortcut = altString + separator + accesskey;
-    tooltip = this.strings.formatStringFromName("markupButton.tooltipWithAccesskey",
-      [shortcut], 1);
-#endif
-    button.setAttribute("tooltiptext", tooltip);
-
-  },
-
-  /**
-   * Toggle the status of the inspector, starting or stopping it. Invoked
-   * from the toolbar's Inspect button.
-   */
-  toggleInspection: function IUI_toggleInspection()
-  {
-    if (!this.isInspectorOpen) {
-      this.openInspectorUI();
-      return;
-    }
-
-    if (this.inspecting) {
-      this.stopInspecting();
-    } else {
-      this.startInspecting();
-    }
-  },
-
-  /**
-   * Show or hide the sidebar. Called from the Styling button on the
-   * highlighter toolbar.
-   */
-  toggleSidebar: function IUI_toggleSidebar()
-  {
-    if (!this.sidebar.visible) {
-      this.sidebar.show();
-    } else {
-      this.sidebar.hide();
-    }
-  },
-
-  /**
-   * Toggle the TreePanel.
-   */
-  toggleHTMLPanel: function IUI_toggleHTMLPanel()
-  {
-    this.currentInspector.toggleMarkup();
-  },
-
-  /**
-   * Is the inspector UI open? Simply check if the toolbar is visible or not.
-   *
-   * @returns boolean
-   */
-  get isInspectorOpen()
-  {
-    return !!(this.toolbar && !this.toolbar.hidden && this.highlighter);
-  },
-
-  /**
-   * Return the default selection element for the inspected document.
-   */
-  get defaultSelection()
-  {
-    let doc = this.win.document;
-    return doc.documentElement ? doc.documentElement.lastElementChild : null;
-  },
-
-  /**
-   * Open inspector UI and HTML tree. Add listeners for document scrolling,
-   * resize, tabContainer.TabSelect and others. If a node is provided, then
-   * start inspecting it.
-   *
-   * @param [optional] aNode
-   *        The node to inspect.
-   */
-  openInspectorUI: function IUI_openInspectorUI(aNode)
-  {
-    // InspectorUI is already up and running. Lock a node if asked (via context).
-    if (this.isInspectorOpen) {
-      if (aNode) {
-        this.inspectNode(aNode);
-        this.stopInspecting();
-      }
-      return;
-    }
-
-    // Observer used to inspect the specified element from content after the
-    // inspector UI has been opened (via the content context menu).
-    function inspectObserver(aElement) {
-      Services.obs.removeObserver(boundInspectObserver,
-                                  INSPECTOR_NOTIFICATIONS.OPENED,
-                                  false);
-      this.inspectNode(aElement);
-      this.stopInspecting();
-    };
-
-    var boundInspectObserver = inspectObserver.bind(this, aNode);
-
-    if (aNode) {
-      // Add the observer to inspect the node after initialization finishes.
-      Services.obs.addObserver(boundInspectObserver,
-                               INSPECTOR_NOTIFICATIONS.OPENED,
-                               false);
-    }
-    // Start initialization.
-    this.browser = this.tabbrowser.selectedBrowser;
-    this.win = this.browser.contentWindow;
-    this.winID = this.getWindowID(this.win);
-    this.toolbar = this.chromeDoc.getElementById("inspector-toolbar");
-    this.inspectCommand = this.chromeDoc.getElementById("Inspector:Inspect");
-
-    // Update menus:
-    this.inspectorUICommand = this.chromeDoc.getElementById("Tools:Inspect");
-    this.inspectorUICommand.setAttribute("checked", "true");
-
-    this.chromeWin.Tilt.setup();
-
-    this.toolbar.hidden = false;
-
-    // initialize the HTML Breadcrumbs
-    this.breadcrumbs = new HTMLBreadcrumbs(this);
-
-    this.isDirty = false;
-
-    this.progressListener = new InspectorProgressListener(this);
-
-    this.chromeWin.addEventListener("keypress", this, false);
-
-    // initialize the highlighter
-    this.highlighter = new Highlighter(this.chromeWin);
-
-    this.initializeStore();
-
-    this._sidebar = new InspectorStyleSidebar({
-      document: this.chromeDoc,
-      inspector: this._currentInspector,
-    });
-
-    // Fade out the highlighter when needed
-    let deck = this.chromeDoc.getElementById("devtools-sidebar-deck");
-    deck.addEventListener("mouseenter", this, true);
-    deck.addEventListener("mouseleave", this, true);
-
-    // Create UI for any sidebars registered with
-    // InspectorUI.registerSidebar()
-    for each (let tool in InspectorUI._registeredSidebars) {
-      this._sidebar.addTool(tool);
-    }
-
-    this.setupNavigationKeys();
-    this.highlighterReady();
-
-    // Focus the first focusable element in the toolbar
-    this.chromeDoc.commandDispatcher.advanceFocusIntoSubtree(this.toolbar);
-
-    // If nothing is focused in the toolbar, it means that the focus manager
-    // is limited to some specific elements and has moved the focus somewhere else.
-    // So in this case, we want to focus the content window.
-    // See: https://developer.mozilla.org/en/XUL_Tutorial/Focus_and_Selection#Platform_Specific_Behaviors
-    if (!this.toolbar.querySelector(":-moz-focusring")) {
-      this.win.focus();
-    }
-
-  },
-
-  /**
-   * Initialize the InspectorStore.
-   */
-  initializeStore: function IUI_initializeStore()
-  {
-    // First time opened, add the TabSelect listener
-    if (this.store.isEmpty()) {
-      this.tabbrowser.tabContainer.addEventListener("TabSelect", this, false);
-    }
-
-    // Has this windowID been inspected before?
-    if (this.store.hasID(this.winID)) {
-      this._currentInspector = this.store.getInspector(this.winID);
-      this._currentInspector._thaw();
-      let selectedNode = this.currentInspector._selectedNode;
-      if (selectedNode) {
-        this.inspectNode(selectedNode);
-      }
-      this.isDirty = this.currentInspector._isDirty;
-    } else {
-      // First time inspecting, set state to no selection + live inspection.
-      let inspector = new Inspector(this);
-      this.store.addInspector(this.winID, inspector);
-      inspector._selectedNode = null;
-      inspector._inspecting = true;
-      inspector._isDirty = this.isDirty;
-
-      inspector._htmlPanelOpen =
-        Services.prefs.getBoolPref("devtools.inspector.htmlPanelOpen");
-
-      inspector._sidebarOpen =
-        Services.prefs.getBoolPref("devtools.inspector.sidebarOpen");
-
-      inspector._activeSidebar =
-        Services.prefs.getCharPref("devtools.inspector.activeSidebar");
-
-      this.win.addEventListener("pagehide", this, true);
-
-      this._currentInspector = inspector;
-    }
-  },
-
-  /**
-   * Browse nodes according to the breadcrumbs layout, only for some specific
-   * elements of the UI.
-   */
-   setupNavigationKeys: function IUI_setupNavigationKeys()
-   {
-     // UI elements that are arrow keys sensitive:
-     // - the Inspector toolbar.
-
-     this.onKeypress = this.onKeypress.bind(this);
-
-     this.toolbar.addEventListener("keypress", this.onKeypress, true);
-   },
-
-  /**
-   * Remove the event listeners for the arrowkeys.
-   */
-   removeNavigationKeys: function IUI_removeNavigationKeys()
-   {
-      this.toolbar.removeEventListener("keypress", this.onKeypress, true);
-   },
-
-  /**
-   * Close inspector UI and associated panels. Unhighlight and stop inspecting.
-   * Remove event listeners for document scrolling, resize,
-   * tabContainer.TabSelect and others.
-   *
-   * @param boolean aKeepInspector
-   *        Tells if you want the inspector associated to the current tab/window to
-   *        be cleared or not. Set this to true to save the inspector, or false
-   *        to destroy it.
-   */
-  closeInspectorUI: function IUI_closeInspectorUI(aKeepInspector)
-  {
-    if (this.closing || !this.win || !this.browser) {
-      return;
-    }
-
-    let winId = new String(this.winID); // retain this to notify observers.
-
-    this.closing = true;
-    this.toolbar.hidden = true;
-
-    this.removeNavigationKeys();
-
-    this.progressListener.destroy();
-    delete this.progressListener;
-
-    if (!aKeepInspector) {
-      this.win.removeEventListener("pagehide", this, true);
-      this.clearPseudoClassLocks();
-    } else {
-      // Update the inspector before closing.
-      if (this.selection) {
-        this.currentInspector._selectedNode = this.selection;
-      }
-      this.currentInspector._inspecting = this.inspecting;
-      this.currentInspector._isDirty = this.isDirty;
-    }
-
-    if (this.store.isEmpty()) {
-      this.tabbrowser.tabContainer.removeEventListener("TabSelect", this, false);
-    }
-
-    this.chromeWin.removeEventListener("keypress", this, false);
-
-    this.stopInspecting();
-
-    // close the sidebar
-    if (this._sidebar) {
-      this._sidebar.destroy();
-      this._sidebar = null;
-    }
-
-    let deck = this.chromeDoc.getElementById("devtools-sidebar-deck");
-    deck.removeEventListener("mouseenter", this, true);
-    deck.removeEventListener("mouseleave", this, true);
-
-    this.highlighter.destroy();
-    this.highlighter = null;
-
-    if (this.breadcrumbs) {
-      this.breadcrumbs.destroy();
-      this.breadcrumbs = null;
-    }
-
-    if (aKeepInspector) {
-      this._currentInspector._freeze();
-    } else {
-      this.store.deleteInspector(this.winID);
-    }
-    delete this._currentInspector;
-
-    this.inspectorUICommand.setAttribute("checked", "false");
-
-    this.browser = this.win = null; // null out references to browser and window
-    this.winID = null;
-    this.selection = null;
-    this.closing = false;
-    this.isDirty = false;
-
-    delete this.stylePanel;
-    delete this.inspectorUICommand;
-    delete this.inspectCommand;
-    delete this.toolbar;
-
-    Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
-
-    if (!aKeepInspector)
-      Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.DESTROYED, winId);
-  },
-
-  /**
-   * Begin inspecting webpage, attach page event listeners, activate
-   * highlighter event listeners.
-   */
-  startInspecting: function IUI_startInspecting()
-  {
-    this.inspectCommand.setAttribute("checked", "true");
-
-    this.inspecting = true;
-    this.highlighter.unlock();
-    this._notifySelected();
-    this._currentInspector.emit("unlocked");
-  },
-
-  _notifySelected: function IUI__notifySelected(aFrom)
-  {
-    this._currentInspector._cancelLayoutChange();
-    this._currentInspector.emit("select", aFrom);
-  },
-
-  /**
-   * Stop inspecting webpage, detach page listeners, disable highlighter
-   * event listeners.
-   * @param aPreventScroll
-   *        Prevent scroll in the HTML tree?
-   */
-  stopInspecting: function IUI_stopInspecting(aPreventScroll)
-  {
-    if (!this.inspecting) {
-      return;
-    }
-
-    this.inspectCommand.setAttribute("checked", "false");
-
-    this.inspecting = false;
-
-    if (this.closing)
-      return;
-
-    if (this.highlighter.getNode()) {
-      this.select(this.highlighter.getNode(), true, !aPreventScroll);
-    } else {
-      this.select(null, true, true);
-    }
-
-    this.highlighter.lock();
-    this._notifySelected();
-    this._currentInspector.emit("locked");
-  },
-
-  /**
-   * Select an object in the inspector.
-   * @param aNode
-   *        node to inspect
-   * @param forceUpdate
-   *        force an update?
-   * @param aScroll boolean
-   *        scroll the tree panel?
-   * @param aFrom [optional] string
-   *        which part of the UI the selection occured from
-   */
-  select: function IUI_select(aNode, forceUpdate, aScroll, aFrom)
-  {
-    if (!aNode)
-      aNode = this.defaultSelection;
-
-    if (forceUpdate || aNode != this.selection) {
-      if (aFrom != "breadcrumbs") {
-        this.clearPseudoClassLocks();
-      }
-
-      this.selection = aNode;
-      if (!this.inspecting) {
-        this.highlighter.highlight(this.selection);
-      }
-    }
-
-    this.breadcrumbs.update();
-    this.chromeWin.Tilt.update(aNode);
-
-    this._notifySelected(aFrom);
-  },
-
-  /**
-   * Toggle the pseudo-class lock on the currently inspected element. If the
-   * pseudo-class is :hover or :active, that pseudo-class will also be toggled
-   * on every ancestor of the element, mirroring real :hover and :active
-   * behavior.
-   * 
-   * @param aPseudo the pseudo-class lock to toggle, e.g. ":hover"
-   */
-  togglePseudoClassLock: function IUI_togglePseudoClassLock(aPseudo)
-  {
-    if (DOMUtils.hasPseudoClassLock(this.selection, aPseudo)) {
-      this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
-        DOMUtils.removePseudoClassLock(crumb.node, aPseudo);
-      });
-    } else {
-      let hierarchical = aPseudo == ":hover" || aPseudo == ":active";
-      let node = this.selection;
-      do {
-        DOMUtils.addPseudoClassLock(node, aPseudo);
-        node = node.parentNode;
-      } while (hierarchical && node.parentNode)
-    }
-    this.nodeChanged("pseudoclass");
-  },
-
-  /**
-   * Clear all pseudo-class locks applied to elements in the node hierarchy
-   */
-  clearPseudoClassLocks: function IUI_clearPseudoClassLocks()
-  {
-    this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
-      if (LayoutHelpers.isNodeConnected(crumb.node)) {
-        DOMUtils.clearPseudoClassLocks(crumb.node);
-      }
-    });
-  },
-
-  /**
-   * Called when the highlighted node is changed by a tool.
-   *
-   * @param object aUpdater
-   *        The tool that triggered the update (if any), that tool's
-   *        onChanged will not be called.
-   */
-  nodeChanged: function IUI_nodeChanged(aUpdater)
-  {
-    this.highlighter.updateInfobar();
-    this.highlighter.invalidateSize();
-    this.breadcrumbs.updateSelectors();
-    this._currentInspector.emit("change", aUpdater);
-  },
-
-  /////////////////////////////////////////////////////////////////////////
-  //// Event Handling
-
-  highlighterReady: function IUI_highlighterReady()
-  {
-    let self = this;
-
-    this.highlighter.addListener("locked", function() {
-      self.stopInspecting();
-    });
-
-    this.highlighter.addListener("unlocked", function() {
-      self.startInspecting();
-    });
-
-    this.highlighter.addListener("nodeselected", function() {
-      self.select(self.highlighter.getNode(), false, false);
-    });
-
-    this.highlighter.addListener("pseudoclasstoggled", function(aPseudo) {
-      self.togglePseudoClassLock(aPseudo);
-    });
-
-    if (this.currentInspector._inspecting) {
-      this.startInspecting();
-      this.highlighter.unlock();
-    } else {
-      this.highlighter.lock();
-    }
-
-    Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.STATE_RESTORED, null);
-
-    this.highlighter.highlight();
-
-    if (this.currentInspector._sidebarOpen) {
-      this._sidebar.show();
-    }
-
-    Services.obs.notifyObservers({wrappedJSObject: this},
-                                 INSPECTOR_NOTIFICATIONS.OPENED, null);
-  },
-
-  /**
-   * Main callback handler for events.
-   *
-   * @param event
-   *        The event to be handled.
-   */
-  handleEvent: function IUI_handleEvent(event)
-  {
-    let winID = null;
-    let win = null;
-    let inspectorClosed = false;
-
-    switch (event.type) {
-      case "TabSelect":
-        winID = this.getWindowID(this.tabbrowser.selectedBrowser.contentWindow);
-        if (this.isInspectorOpen && winID != this.winID) {
-          this.closeInspectorUI(true);
-          inspectorClosed = true;
-        }
-
-        if (winID && this.store.hasID(winID)) {
-          if (inspectorClosed && this.closing) {
-            Services.obs.addObserver(function reopenInspectorForTab() {
-              Services.obs.removeObserver(reopenInspectorForTab,
-                INSPECTOR_NOTIFICATIONS.CLOSED, false);
-
-              this.openInspectorUI();
-            }.bind(this), INSPECTOR_NOTIFICATIONS.CLOSED, false);
-          } else {
-            this.openInspectorUI();
-          }
-        }
-
-        if (this.store.isEmpty()) {
-          this.tabbrowser.tabContainer.removeEventListener("TabSelect", this,
-                                                         false);
-        }
-        break;
-      case "keypress":
-        switch (event.keyCode) {
-          case this.chromeWin.KeyEvent.DOM_VK_ESCAPE:
-            this.closeInspectorUI(false);
-            event.preventDefault();
-            event.stopPropagation();
-            break;
-      }
-      case "pagehide":
-        win = event.originalTarget.defaultView;
-        // Skip iframes/frames.
-        if (!win || win.frameElement || win.top != win) {
-          break;
-        }
-
-        win.removeEventListener(event.type, this, true);
-
-        winID = this.getWindowID(win);
-        if (winID && winID != this.winID) {
-          this.store.deleteInspector(winID);
-        }
-
-        if (this.store.isEmpty()) {
-          this.tabbrowser.tabContainer.removeEventListener("TabSelect", this,
-                                                         false);
-        }
-        break;
-      case "mouseleave":
-        this.highlighter.show();
-        break;
-      case "mouseenter":
-        this.highlighter.hide();
-        break;
-    }
-  },
-
-  /*
-   * handles "keypress" events.
-  */
-  onKeypress: function IUI_onKeypress(event)
-  {
-    let node = null;
-    let bc = this.breadcrumbs;
-    switch (event.keyCode) {
-      case this.chromeWin.KeyEvent.DOM_VK_LEFT:
-        if (bc.currentIndex != 0)
-          node = bc.nodeHierarchy[bc.currentIndex - 1].node;
-        if (node && this.highlighter.isNodeHighlightable(node))
-          this.highlighter.highlight(node);
-        event.preventDefault();
-        event.stopPropagation();
-        break;
-      case this.chromeWin.KeyEvent.DOM_VK_RIGHT:
-        if (bc.currentIndex < bc.nodeHierarchy.length - 1)
-          node = bc.nodeHierarchy[bc.currentIndex + 1].node;
-        if (node && this.highlighter.isNodeHighlightable(node)) {
-          this.highlighter.highlight(node);
-        }
-        event.preventDefault();
-        event.stopPropagation();
-        break;
-      case this.chromeWin.KeyEvent.DOM_VK_UP:
-        if (this.selection) {
-          // Find a previous sibling that is highlightable.
-          node = this.selection.previousSibling;
-          while (node && !this.highlighter.isNodeHighlightable(node)) {
-            node = node.previousSibling;
-          }
-        }
-        if (node && this.highlighter.isNodeHighlightable(node)) {
-          this.highlighter.highlight(node, true);
-        }
-        event.preventDefault();
-        event.stopPropagation();
-        break;
-      case this.chromeWin.KeyEvent.DOM_VK_DOWN:
-        if (this.selection) {
-          // Find a next sibling that is highlightable.
-          node = this.selection.nextSibling;
-          while (node && !this.highlighter.isNodeHighlightable(node)) {
-            node = node.nextSibling;
-          }
-        }
-        if (node && this.highlighter.isNodeHighlightable(node)) {
-          this.highlighter.highlight(node, true);
-        }
-        event.preventDefault();
-        event.stopPropagation();
-        break;
-    }
-  },
-
-  /**
-   * Return the currently-selected node for the purposes of the
-   * context menu.  This is usually the highlighter selection, unless
-   * the markup panel has a selected node that can't be highlighted
-   * (such as a text node).  This will be fixed once the highlighter/inspector
-   * is confortable with non-element nodes being the current selection.
-   * See bug 785180.
-   */
-  _contextSelection: function IUI__contextSelection()
-  {
-    let inspector = this.currentInspector;
-    if (inspector.markup) {
-      return inspector.markup.selected;
-    }
-    return this.selection;
-  },
-
-  /**
-   * Copy the innerHTML of the selected Node to the clipboard. Called via the
-   * Inspector:CopyInner command.
-   */
-  copyInnerHTML: function IUI_copyInnerHTML()
-  {
-    let selection = this._contextSelection();
-    clipboardHelper.copyString(selection.innerHTML, selection.ownerDocument);
-  },
-
-  /**
-   * Copy the outerHTML of the selected Node to the clipboard. Called via the
-   * Inspector:CopyOuter command.
-   */
-  copyOuterHTML: function IUI_copyOuterHTML()
-  {
-    let selection = this._contextSelection();
-    clipboardHelper.copyString(selection.outerHTML, selection.ownerDocument);
-  },
-
-  /**
-   * Delete the selected node. Called via the Inspector:DeleteNode command.
-   */
-  deleteNode: function IUI_deleteNode()
-  {
-    let selection = this._contextSelection();
-
-    let root = selection.ownerDocument.documentElement;
-    if (selection === root) {
-      // We can't delete the root element.
-      return;
-    }
-
-    let parent = selection.parentNode;
-
-    // If the markup panel is active, use the markup panel to delete
-    // the node, making this an undoable action.
-    let markup = this.currentInspector.markup;
-    if (markup) {
-      markup.deleteNode(selection);
-    } else {
-      // remove the node from content
-      parent.removeChild(selection);
-    }
-