--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1050,16 +1050,19 @@ pref("devtools.inspector.activeSidebar",
pref("devtools.layoutview.enabled", false);
pref("devtools.layoutview.open", false);
// Enable the Debugger
pref("devtools.debugger.enabled", false);
pref("devtools.debugger.remote-enabled", false);
pref("devtools.debugger.remote-host", "localhost");
pref("devtools.debugger.remote-port", 6000);
+pref("devtools.debugger.remote-autoconnect", false);
+pref("devtools.debugger.remote-connection-retries", 3);
+pref("devtools.debugger.remote-timeout", 3000);
// The default Debugger UI height
pref("devtools.debugger.ui.height", 250);
pref("devtools.debugger.ui.remote-win.width", 900);
pref("devtools.debugger.ui.remote-win.height", 400);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -41,16 +41,17 @@
* ***** END LICENSE BLOCK ***** */
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const DBG_XUL = "chrome://browser/content/debugger.xul";
+const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const REMOTE_PROFILE_NAME = "_remote-debug";
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let EXPORTED_SYMBOLS = ["DebuggerUI"];
@@ -77,71 +78,89 @@ DebuggerUI.prototype = {
if (tab._scriptDebugger) {
tab._scriptDebugger.close();
return null;
}
return new DebuggerPane(tab);
},
/**
- * Starts a remote debugger in a new process, or stops it if already started.
- * @see DebuggerProcess.constructor
- * @return DebuggerProcess if the debugger is started, null if it's stopped.
+ * Starts a remote debugger in a new window, or stops it if already started.
+ * @return RemoteDebuggerWindow if the debugger is started, null if stopped.
*/
- toggleRemoteDebugger: function DUI_toggleRemoteDebugger(aOnClose, aOnRun) {
+ toggleRemoteDebugger: function DUI_toggleRemoteDebugger() {
let win = this.chromeWindow;
if (win._remoteDebugger) {
win._remoteDebugger.close();
return null;
}
- return new DebuggerProcess(win, aOnClose, aOnRun);
+ return new RemoteDebuggerWindow(this);
},
/**
* Starts a chrome debugger in a new process, or stops it if already started.
- * @see DebuggerProcess.constructor
- * @return DebuggerProcess if the debugger is started, null if it's stopped.
+ * @return ChromeDebuggerProcess if the debugger is started, null if stopped.
*/
toggleChromeDebugger: function DUI_toggleChromeDebugger(aOnClose, aOnRun) {
let win = this.chromeWindow;
if (win._chromeDebugger) {
win._chromeDebugger.close();
return null;
}
- return new DebuggerProcess(win, aOnClose, aOnRun, true);
+ return new ChromeDebuggerProcess(win, aOnClose, aOnRun, true);
},
/**
* Get the debugger for a specified tab.
- * @return DebuggerPane if a debugger exists for the tab, null otherwise
+ * @return DebuggerPane if a debugger exists for the tab, null otherwise.
*/
getDebugger: function DUI_getDebugger(aTab) {
return aTab._scriptDebugger;
},
/**
+ * Get the remote debugger for the current chrome window.
+ * @return RemoteDebuggerWindow if a remote debugger exists, null otherwise.
+ */
+ getRemoteDebugger: function DUI_getRemoteDebugger() {
+ let win = this.chromeWindow;
+ return '_remoteDebugger' in win ? win._remoteDebugger : null;
+ },
+
+ /**
+ * Get the chrome debugger for the current firefox instance.
+ * @return ChromeDebuggerProcess if a chrome debugger exists, null otherwise.
+ */
+ getChromeDebugger: function DUI_getChromeDebugger() {
+ let win = this.chromeWindow;
+ return '_chromeDebugger' in win ? win._chromeDebugger : null;
+ },
+
+ /**
* Get the preferences associated with the debugger frontend.
* @return object
*/
get preferences() {
return DebuggerPreferences;
}
};
/**
* Creates a pane that will host the debugger.
*
+ * @param DebuggerUI aDebuggerUI
+ * The parent instance creating the new debugger.
* @param XULElement aTab
* The tab in which to create the debugger.
*/
function DebuggerPane(aTab) {
this._tab = aTab;
-
+
this._initServer();
this._create();
}
DebuggerPane.prototype = {
/**
* Initializes the debugger server.
@@ -176,17 +195,17 @@ DebuggerPane.prototype = {
let self = this;
this._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
self._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
self._frame.addEventListener("Debugger:Close", self.close, true);
self._frame.addEventListener("unload", self.close, true);
// Bind shortcuts for accessing the breakpoint methods in the debugger.
- let bkp = self.debuggerWindow.DebuggerController.Breakpoints;
+ let bkp = self.contentWindow.DebuggerController.Breakpoints;
self.addBreakpoint = bkp.addBreakpoint;
self.removeBreakpoint = bkp.removeBreakpoint;
self.getBreakpoint = bkp.getBreakpoint;
}, true);
this._frame.setAttribute("src", DBG_XUL);
},
@@ -211,57 +230,134 @@ DebuggerPane.prototype = {
this._frame = null;
this._nbox = null;
},
/**
* Gets the debugger content window.
* @return nsIDOMWindow if a debugger window exists, null otherwise
*/
- get debuggerWindow() {
+ get contentWindow() {
return this._frame ? this._frame.contentWindow : null;
},
/**
* Shortcut for accessing the list of breakpoints in the debugger.
* @return object if a debugger window exists, null otherwise
*/
get breakpoints() {
- let debuggerWindow = this.debuggerWindow;
- if (debuggerWindow) {
- return debuggerWindow.DebuggerController.Breakpoints.store;
+ let contentWindow = this.contentWindow;
+ if (contentWindow) {
+ return contentWindow.DebuggerController.Breakpoints.store;
}
return null;
}
};
/**
- * Creates a process that will hold the remote debugger.
+ * Creates a window that will host a remote debugger.
+ *
+ * @param DebuggerUI aDebuggerUI
+ * The parent instance creating the new debugger.
+ */
+function RemoteDebuggerWindow(aDebuggerUI) {
+ this._globalUI = aDebuggerUI;
+ this._win = aDebuggerUI.chromeWindow;
+
+ this._create();
+}
+
+RemoteDebuggerWindow.prototype = {
+
+ /**
+ * Creates and initializes the widgets containing the remote debugger UI.
+ */
+ _create: function DP__create() {
+ this._win._remoteDebugger = this;
+
+ this._dbgwin = this._globalUI.chromeWindow.open(DBG_XUL,
+ L10N.getStr("remoteDebuggerWindowTitle"),
+ "width=" + DebuggerPreferences.remoteWinWidth + "," +
+ "height=" + DebuggerPreferences.remoteWinHeight + "," +
+ "chrome,dependent,resizable,centerscreen");
+
+ this._dbgwin._remoteFlag = true;
+
+ this.close = this.close.bind(this);
+ let self = this;
+
+ this._dbgwin.addEventListener("Debugger:Loaded", function dbgLoaded() {
+ self._dbgwin.removeEventListener("Debugger:Loaded", dbgLoaded, true);
+ self._dbgwin.addEventListener("Debugger:Close", self.close, true);
+ self._dbgwin.addEventListener("unload", self.close, true);
+
+ // Bind shortcuts for accessing the breakpoint methods in the debugger.
+ let bkp = self.contentWindow.DebuggerController.Breakpoints;
+ self.addBreakpoint = bkp.addBreakpoint;
+ self.removeBreakpoint = bkp.removeBreakpoint;
+ self.getBreakpoint = bkp.getBreakpoint;
+ }, true);
+ },
+
+ /**
+ * Closes the remote debugger, along with the parent window if necessary.
+ */
+ close: function DP_close() {
+ if (!this._win) {
+ return;
+ }
+ delete this._win._remoteDebugger;
+ this._win = null;
+
+ this._dbgwin.close();
+ this._dbgwin = null;
+ },
+
+ /**
+ * Gets the remote debugger content window.
+ * @return nsIDOMWindow if a debugger window exists, null otherwise.
+ */
+ get contentWindow() {
+ return this._dbgwin;
+ },
+
+ /**
+ * Shortcut for accessing the list of breakpoints in the remote debugger.
+ * @return object if a debugger window exists, null otherwise.
+ */
+ get breakpoints() {
+ let contentWindow = this.contentWindow;
+ if (contentWindow) {
+ return contentWindow.DebuggerController.Breakpoints.store;
+ }
+ return null;
+ }
+};
+
+/**
+ * Creates a process that will hold a chrome debugger.
*
* @param function aOnClose
* Optional, a function called when the process exits.
* @param function aOnRun
* Optional, a function called when the process starts running.
- * @param boolean aInitServerFlag
- * True to initialize the server. This should happen only in the chrome
- * debugging case. This should also be true by default after bug #747429.
* @param nsIDOMWindow aWindow
- * The chrome window for which the remote debugger instance is created.
+ * The chrome window for which the debugger instance is created.
*/
-function DebuggerProcess(aWindow, aOnClose, aOnRun, aInitServerFlag) {
+function ChromeDebuggerProcess(aWindow, aOnClose, aOnRun) {
this._win = aWindow;
this._closeCallback = aOnClose;
this._runCallback = aOnRun;
- aInitServerFlag && this._initServer();
+ this._initServer();
this._initProfile();
this._create();
}
-DebuggerProcess.prototype = {
+ChromeDebuggerProcess.prototype = {
/**
* Initializes the debugger server.
*/
_initServer: function RDP__initServer() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
@@ -288,17 +384,17 @@ DebuggerProcess.prototype = {
this._dbgProfile = profileService.createProfile(null, null, dbgProfileName);
profileService.flush();
},
/**
* Creates and initializes the profile & process for the remote debugger.
*/
_create: function RDP__create() {
- this._win._remoteDebugger = this;
+ this._win._chromeDebugger = this;
let file = FileUtils.getFile("CurProcD",
[Services.appinfo.OS == "WINNT" ? "firefox.exe"
: "firefox-bin"]);
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(file);
@@ -318,17 +414,17 @@ DebuggerProcess.prototype = {
/**
* Closes the remote debugger, removing the profile and killing the process.
*/
close: function RDP_close() {
if (!this._win) {
return;
}
- delete this._win._remoteDebugger;
+ delete this._win._chromeDebugger;
this._win = null;
if (this._dbgProcess.isRunning) {
this._dbgProcess.kill();
}
if (this._dbgProfile) {
this._dbgProfile.remove(false);
}
@@ -337,16 +433,36 @@ DebuggerProcess.prototype = {
}
this._dbgProcess = null;
this._dbgProfile = null;
}
};
/**
+ * Localization convenience methods.
+ */
+let L10N = {
+
+ /**
+ * L10N shortcut function.
+ *
+ * @param string aName
+ * @return string
+ */
+ getStr: function L10N_getStr(aName) {
+ return this.stringBundle.GetStringFromName(aName);
+ }
+};
+
+XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
+ return Services.strings.createBundle(DBG_STRINGS_URI);
+});
+
+/**
* Various debugger preferences.
*/
let DebuggerPreferences = {
/**
* Gets the preferred height of the debugger pane.
* @return number
*/
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -82,16 +82,17 @@ let DebuggerController = {
}
this._isInitialized = true;
window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
DebuggerView.initializeEditor();
DebuggerView.StackFrames.initialize();
DebuggerView.Properties.initialize();
DebuggerView.Scripts.initialize();
+ DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
this.dispatchEvent("Debugger:Loaded");
this._connect();
},
/**
* Destroys the debugger view, disconnects the debugger client and cleans up
* any active listeners.
@@ -109,27 +110,74 @@ let DebuggerController = {
DebuggerView.Properties.destroy();
DebuggerController.SourceScripts.disconnect();
DebuggerController.StackFrames.disconnect();
DebuggerController.ThreadState.disconnect();
this.dispatchEvent("Debugger:Unloaded");
this._disconnect();
- this._isRemote && this._quitApp();
+ this._isChromeDebugger && this._quitApp();
+ },
+
+ /**
+ * Prepares the hostname and port number for a remote debugger connection
+ * and handles connection retries and timeouts.
+ *
+ * @return boolean true if connection should proceed normally
+ */
+ _prepareConnection: function DC__prepareConnection() {
+ // If we exceeded the total number of connection retries, bail.
+ if (this._remoteConnectionTry === Prefs.remoteConnectionRetries) {
+ Services.prompt.alert(null,
+ L10N.getStr("remoteDebuggerPromptTitle"),
+ L10N.getStr("remoteDebuggerConnectionFailedMessage"));
+ this.dispatchEvent("Debugger:Close");
+ return false;
+ }
+
+ // TODO: This is ugly, need to rethink the design for the UI in #751677.
+ if (!Prefs.remoteAutoConnect) {
+ let prompt = new RemoteDebuggerPrompt();
+ let result = prompt.show(!!this._remoteConnectionTimeout);
+ if (!result) {
+ this.dispatchEvent("Debugger:Close");
+ return false;
+ }
+ Prefs.remoteHost = prompt.uri.host;
+ Prefs.remotePort = prompt.uri.port;
+ }
+
+ // If this debugger is connecting remotely to a server, we need to check
+ // after a while if the connection actually succeeded.
+ this._remoteConnectionTry = ++this._remoteConnectionTry || 1;
+ this._remoteConnectionTimeout = window.setTimeout(function() {
+ // If we couldn't connect to any server yet, try again...
+ if (!DebuggerController.activeThread) {
+ DebuggerController._connect();
+ }
+ }, Prefs.remoteTimeout);
+
+ return true;
},
/**
* Initializes a debugger client and connects it to the debugger server,
* wiring event handlers as necessary.
*/
_connect: function DC__connect() {
- let transport =
- this._isRemote ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
- : DebuggerServer.connectPipe();
+ if (this._isRemoteDebugger) {
+ if (!this._prepareConnection()) {
+ return;
+ }
+ }
+
+ let transport = (this._isChromeDebugger || this._isRemoteDebugger)
+ ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
+ : DebuggerServer.connectPipe();
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) {
@@ -218,18 +266,26 @@ let DebuggerController = {
}.bind(this));
}.bind(this));
},
/**
* Returns true if this is a remote debugger instance.
* @return boolean
*/
- get _isRemote() {
- return !window.parent.content;
+ get _isRemoteDebugger() {
+ return window._remoteFlag;
+ },
+
+ /**
+ * Returns true if this is a chrome debugger instance.
+ * @return boolean
+ */
+ get _isChromeDebugger() {
+ return !window.parent.content && !this._isRemoteDebugger;
},
/**
* Attempts to quit the current process if allowed.
*/
_quitApp: function DC__quitApp() {
let canceled = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
@@ -1320,17 +1376,39 @@ let L10N = {
XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
return Services.strings.createBundle(DBG_STRINGS_URI);
});
/**
* Shortcuts for accessing various debugger preferences.
*/
-let Prefs = {};
+let Prefs = {
+
+ /**
+ * Gets a flag specifying if the the debugger should automatically connect to
+ * the default host and port number.
+ * @return boolean
+ */
+ get remoteAutoConnect() {
+ if (this._autoConn === undefined) {
+ this._autoConn = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
+ }
+ return this._autoConn;
+ },
+
+ /**
+ * Sets a flag specifying if the the debugger should automatically connect.
+ * @param boolean value
+ */
+ set remoteAutoConnect(value) {
+ Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", value);
+ this._autoConn = value;
+ }
+};
/**
* Gets the preferred default remote debugging host.
* @return string
*/
XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() {
return Services.prefs.getCharPref("devtools.debugger.remote-host");
});
@@ -1339,16 +1417,32 @@ XPCOMUtils.defineLazyGetter(Prefs, "remo
* Gets the preferred default remote debugging port.
* @return number
*/
XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() {
return Services.prefs.getIntPref("devtools.debugger.remote-port");
});
/**
+ * Gets the max number of attempts to reconnect to a remote server.
+ * @return number
+ */
+XPCOMUtils.defineLazyGetter(Prefs, "remoteConnectionRetries", function() {
+ return Services.prefs.getIntPref("devtools.debugger.remote-connection-retries");
+});
+
+/**
+ * Gets the remote debugging connection timeout (in milliseconds).
+ * @return number
+ */
+XPCOMUtils.defineLazyGetter(Prefs, "remoteTimeout", function() {
+ return Services.prefs.getIntPref("devtools.debugger.remote-timeout");
+});
+
+/**
* Preliminary setup for the DebuggerController object.
*/
DebuggerController.init();
DebuggerController.ThreadState = new ThreadState();
DebuggerController.StackFrames = new StackFrames();
DebuggerController.SourceScripts = new SourceScripts();
DebuggerController.Breakpoints = new Breakpoints();
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -77,16 +77,71 @@ let DebuggerView = {
},
/**
* The load event handler for the source editor. This method does post-load
* editor initialization.
*/
_onEditorLoad: function DV__onEditorLoad() {
DebuggerController.Breakpoints.initialize();
+ },
+
+ /**
+ * Sets the close button hidden or visible. It's hidden by default.
+ * @param boolean aVisibleFlag
+ */
+ showCloseButton: function DV_showCloseButton(aVisibleFlag) {
+ document.getElementById("close").setAttribute("hidden", !aVisibleFlag);
+ }
+};
+
+/**
+ * A simple way of displaying a "Connect to..." prompt.
+ */
+function RemoteDebuggerPrompt() {
+
+ /**
+ * The remote uri the user wants to connect to.
+ */
+ this.uri = null;
+}
+
+RemoteDebuggerPrompt.prototype = {
+
+ /**
+ * Shows the prompt and sets the uri using the user input.
+ *
+ * @param boolean aIsReconnectingFlag
+ * True to show the reconnect message instead.
+ */
+ show: function RDP_show(aIsReconnectingFlag) {
+ let check = { value: Prefs.remoteAutoConnect };
+ let input = { value: "http://" + Prefs.remoteHost +
+ ":" + Prefs.remotePort + "/" };
+
+ while (true) {
+ let result = Services.prompt.prompt(null,
+ L10N.getStr("remoteDebuggerPromptTitle"),
+ L10N.getStr(aIsReconnectingFlag
+ ? "remoteDebuggerReconnectMessage"
+ : "remoteDebuggerPromptMessage"), input,
+ L10N.getStr("remoteDebuggerPromptCheck"), check);
+
+ Prefs.remoteAutoConnect = check.value;
+
+ try {
+ let uri = Services.io.newURI(input.value, null, null);
+ let url = uri.QueryInterface(Ci.nsIURL);
+
+ // If a url could be successfully retrieved, then the uri is correct.
+ this.uri = uri;
+ return result;
+ }
+ catch(e) { }
+ }
}
};
/**
* Functions handling the scripts UI.
*/
function ScriptsView() {
this._onScriptsChange = this._onScriptsChange.bind(this);
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -70,17 +70,17 @@
</xul:popupset>
<xul:commandset id="editMenuCommands"/>
<xul:commandset id="sourceEditorCommands"/>
<xul:keyset id="sourceEditorKeys"/>
<div id="body" class="vbox flex">
<xul:toolbar id="dbg-toolbar">
- <xul:button id="close">&debuggerUI.closeButton;</xul:button>
+ <xul:button id="close" hidden="false">&debuggerUI.closeButton;</xul:button>
<xul:button id="resume"/>
<xul:button id="step-over">&debuggerUI.stepOverButton;</xul:button>
<xul:button id="step-in">&debuggerUI.stepInButton;</xul:button>
<xul:button id="step-out">&debuggerUI.stepOutButton;</xul:button>
<xul:menulist id="scripts"/>
<xul:textbox id="scripts-search" type="search"
emptytext="&debuggerUI.emptyFilterText;"/>
</xul:toolbar>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -42,16 +42,17 @@ srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/devtools/debugger/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_dbg_createRemote.js \
+ browser_dbg_createChrome.js \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \
browser_dbg_tabactor-02.js \
browser_dbg_contextactor-01.js \
browser_dbg_contextactor-02.js \
testactors.js \
browser_dbg_nav-01.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
+++ b/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js
@@ -25,17 +25,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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;
executeSoon(startTest);
});
executeSoon(function() {
--- 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;
executeSoon(startTest);
});
executeSoon(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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testCleanExit();
});
}
function testCleanExit() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_createChrome.js
@@ -0,0 +1,89 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that a chrome debugger can be created in a new process.
+
+var gProcess = null;
+var gTab = null;
+var gDebuggee = null;
+
+function test() {
+ debug_chrome(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) {
+ gTab = aTab;
+ gDebuggee = aDebuggee;
+ gProcess = aProcess;
+
+ testSimpleCall();
+ });
+}
+
+function testSimpleCall() {
+ Services.tm.currentThread.dispatch({ run: function() {
+
+ ok(gProcess._dbgProcess,
+ "The remote debugger process wasn't created properly!");
+ ok(gProcess._dbgProcess.isRunning,
+ "The remote debugger process isn't running!");
+ is(typeof gProcess._dbgProcess.pid, "number",
+ "The remote debugger process doesn't have a pid (?!)");
+
+ info("process location: " + gProcess._dbgProcess.location);
+ info("process pid: " + gProcess._dbgProcess.pid);
+ info("process name: " + gProcess._dbgProcess.processName);
+ info("process sig: " + gProcess._dbgProcess.processSignature);
+
+ ok(gProcess._dbgProfile,
+ "The remote debugger profile wasn't created properly!");
+ ok(gProcess._dbgProfile.localDir,
+ "The remote debugger profile doesn't have a localDir...");
+ ok(gProcess._dbgProfile.rootDir,
+ "The remote debugger profile doesn't have a rootDir...");
+ ok(gProcess._dbgProfile.name,
+ "The remote debugger profile doesn't have a name...");
+
+ info("profile localDir: " + gProcess._dbgProfile.localDir);
+ info("profile rootDir: " + gProcess._dbgProfile.rootDir);
+ info("profile name: " + gProcess._dbgProfile.name);
+
+ let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
+ .createInstance(Ci.nsIToolkitProfileService);
+
+ let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
+
+ ok(profile,
+ "The remote debugger profile wasn't *actually* created properly!");
+ is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
+ "The remote debugger profile doesn't have the correct localDir!");
+ is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
+ "The remote debugger profile doesn't have the correct rootDir!");
+
+ DebuggerUI.toggleChromeDebugger();
+ }}, 0);
+}
+
+function aOnClosing() {
+ ok(!gProcess._dbgProcess.isRunning,
+ "The remote debugger process isn't closed as it should be!");
+ is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
+ "The remote debugger process didn't die cleanly.");
+
+ info("process exit value: " + gProcess._dbgProcess.exitValue);
+
+ info("profile localDir: " + gProcess._dbgProfile.localDir.path);
+ info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
+ info("profile name: " + gProcess._dbgProfile.name);
+
+ executeSoon(function() {
+ finish();
+ });
+}
+
+registerCleanupFunction(function() {
+ removeTab(gTab);
+ gProcess = null;
+ gTab = null;
+ gDebuggee = null;
+});
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js
+++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js
@@ -1,86 +1,80 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-var gProcess = null;
+
+// Tests that a remote debugger can be created in a new window.
+
+var gWindow = null;
var gTab = null;
-var gDebuggee = null;
+var gAutoConnect = null;
+
+const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
function test() {
- remote_debug_tab_pane(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) {
+ debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
gTab = aTab;
- gDebuggee = aDebuggee;
- gProcess = aProcess;
+ gWindow = aWindow;
+ let gDebugger = gWindow.contentWindow;
- testSimpleCall();
- });
-}
+ is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
+ "The close button should be hidden in a remote debugger.");
-function testSimpleCall() {
- Services.tm.currentThread.dispatch({ run: function() {
+ is(gDebugger.DebuggerController.activeThread.paused, false,
+ "Should be running after debug_remote.");
- ok(gProcess._dbgProcess,
- "The remote debugger process wasn't created properly!");
- ok(gProcess._dbgProcess.isRunning,
- "The remote debugger process isn't running!");
- is(typeof gProcess._dbgProcess.pid, "number",
- "The remote debugger process doesn't have a pid (?!)");
+ gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
+ Services.tm.currentThread.dispatch({ run: function() {
+
+ let frames = gDebugger.DebuggerView.StackFrames._frames;
+ let childNodes = frames.childNodes;
- info("process location: " + gProcess._dbgProcess.location);
- info("process pid: " + gProcess._dbgProcess.pid);
- info("process name: " + gProcess._dbgProcess.processName);
- info("process sig: " + gProcess._dbgProcess.processSignature);
+ is(gDebugger.DebuggerController.activeThread.paused, true,
+ "Should be paused after an interrupt request.");
- ok(gProcess._dbgProfile,
- "The remote debugger profile wasn't created properly!");
- ok(gProcess._dbgProfile.localDir,
- "The remote debugger profile doesn't have a localDir...");
- ok(gProcess._dbgProfile.rootDir,
- "The remote debugger profile doesn't have a rootDir...");
- ok(gProcess._dbgProfile.name,
- "The remote debugger profile doesn't have a name...");
+ is(frames.querySelectorAll(".dbg-stackframe").length, 1,
+ "Should have one frame in the stack.");
- info("profile localDir: " + gProcess._dbgProfile.localDir);
- info("profile rootDir: " + gProcess._dbgProfile.rootDir);
- info("profile name: " + gProcess._dbgProfile.name);
-
- let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
- .createInstance(Ci.nsIToolkitProfileService);
+ gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
+ Services.tm.currentThread.dispatch({ run: function() {
+ closeDebuggerAndFinish(gTab, true);
+ }}, 0);
+ });
- let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
+ EventUtils.sendMouseEvent({ type: "click" },
+ gDebugger.document.getElementById("resume"),
+ gDebugger);
+ }}, 0);
+ });
- ok(profile,
- "The remote debugger profile wasn't *actually* created properly!");
- is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
- "The remote debugger profile doesn't have the correct localDir!");
- is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
- "The remote debugger profile doesn't have the correct rootDir!");
+ let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0];
+
+ is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
- DebuggerUI.toggleRemoteDebugger();
- }}, 0);
-}
+ iframe.runDebuggerStatement();
+ },
+ function beforeTabAdded() {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+ DebuggerServer.closeListener();
-function aOnClosing() {
- ok(!gProcess._dbgProcess.isRunning,
- "The remote debugger process isn't closed as it should be!");
- is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
- "The remote debugger process didn't die cleanly.");
+ gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
+ Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
- info("process exit value: " + gProcess._dbgProcess.exitValue);
-
- info("profile localDir: " + gProcess._dbgProfile.localDir.path);
- info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
- info("profile name: " + gProcess._dbgProfile.name);
-
- executeSoon(function() {
- finish();
+ // Open the listener at some point in the future to test automatic reconnect.
+ window.setTimeout(function() {
+ DebuggerServer.openListener(
+ Services.prefs.getIntPref("devtools.debugger.remote-port"));
+ }, Math.random() * 1000);
});
}
registerCleanupFunction(function() {
+ Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
removeTab(gTab);
- gProcess = null;
+ gWindow = null;
gTab = null;
- gDebuggee = null;
+ gAutoConnect = null;
});
--- a/browser/devtools/debugger/test/browser_dbg_displayName.js
+++ b/browser/devtools/debugger/test/browser_dbg_displayName.js
@@ -10,17 +10,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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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,17 +9,20 @@ 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.debuggerWindow;
+ let gDebugger = gPane.contentWindow;
+
+ is(gDebugger.document.getElementById("close").getAttribute("hidden"), "false",
+ "The close button should be visible in a normal content debugger.");
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._frames;
--- 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js
+++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js
@@ -7,17 +7,17 @@
var gPane = null;
var gTab = null;
var gDebugger = null;
function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
- gDebugger = gPane.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testPause();
});
}
function testPause() {
is(gDebugger.DebuggerController.activeThread.paused, false,
"Should be running after debug_tab_pane.");
--- 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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,28 +8,31 @@ 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testSimpleCall();
});
}
function testSimpleCall() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
let localScope = gDebugger.DebuggerView.Properties.localScope;
+ globalScope.empty();
+ localScope.empty();
+
let windowVar = globalScope.addVar("window");
let documentVar = globalScope.addVar("document");
let localVar0 = localScope.addVar("localVariable");
let localVar1 = localScope.addVar("localVar1");
let localVar2 = localScope.addVar("localVar2");
let localVar3 = localScope.addVar("localVar3");
let localVar4 = localScope.addVar("localVar4");
let localVar5 = localScope.addVar("localVar5");
@@ -74,20 +77,28 @@ function testSimpleCall() {
ok(localVar0, "The localVar0 hasn't been created correctly.");
ok(localVar1, "The localVar1 hasn't been created correctly.");
ok(localVar2, "The localVar2 hasn't been created correctly.");
ok(localVar3, "The localVar3 hasn't been created correctly.");
ok(localVar4, "The localVar4 hasn't been created correctly.");
ok(localVar5, "The localVar5 hasn't been created correctly.");
+ for each (let elt in globalScope.querySelector(".details").childNodes) {
+ info("globalScope :: " + {
+ id: elt.id, className: elt.className }.toSource());
+ }
is(globalScope.querySelector(".details").childNodes.length, 2,
"The globalScope doesn't contain all the created variable elements.");
- is(localScope.querySelector(".details").childNodes.length, 7,
+ for each (let elt in localScope.querySelector(".details").childNodes) {
+ info("localScope :: " + {
+ id: elt.id, className: elt.className }.toSource());
+ }
+ is(localScope.querySelector(".details").childNodes.length, 6,
"The localScope doesn't contain all the created variable elements.");
is(localVar5.querySelector(".details").childNodes.length, 6,
"The localVar5 doesn't contain all the created properties.");
is(localVar5.someProp5.querySelector(".details").childNodes.length, 6,
"The localVar5.someProp5 doesn't contain all the created properties.");
--- 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testFrameParameters();
});
}
function testFrameParameters()
{
dump("Started testFrameParameters!\n");
--- 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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
@@ -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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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
@@ -17,17 +17,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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
testRecurse();
});
}
function testRecurse() {
gDebuggee.gRecurseLimit = (gDebugger.DebuggerController.StackFrames.pageSize * 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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
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.debuggerWindow;
+ gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;
executeSoon(startTest);
});
executeSoon(function() {
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -44,22 +44,26 @@ function addTab(aURL, aOnload)
return tab;
}
function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
-function closeDebuggerAndFinish(aTab) {
+function closeDebuggerAndFinish(aTab, aRemoteFlag) {
DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
finish();
}, false);
- DebuggerUI.getDebugger(aTab).close();
+ if (!aRemoteFlag) {
+ DebuggerUI.getDebugger(aTab).close();
+ } else {
+ DebuggerUI.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;
@@ -94,28 +98,49 @@ function debug_tab_pane(aURL, aOnDebuggi
gBrowser.selectedTab = gTab;
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
let pane = DebuggerUI.toggleDebugger();
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume...
- pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
+ pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
aOnDebugging(tab, debuggee, pane);
});
}, true);
});
}
-function remote_debug_tab_pane(aURL, aOnClosing, aOnDebugging)
+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:Connecting", function dbgConnected() {
+ win._dbgwin.removeEventListener("Debugger:Connecting", dbgConnected, true);
+
+ // Wait for the initial resume...
+ win.contentWindow.gClient.addOneTimeListener("resumed", function() {
+ aOnDebugging(tab, debuggee, win);
+ });
+ }, true);
+ });
+}
+
+function debug_chrome(aURL, aOnClosing, aOnDebugging)
{
let tab = addTab(aURL, function() {
gBrowser.selectedTab = gTab;
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
- DebuggerUI.toggleRemoteDebugger(aOnClosing, function dbgRan(process) {
+ DebuggerUI.toggleChromeDebugger(aOnClosing, function dbgRan(process) {
// Wait for the remote debugging process to start...
aOnDebugging(tab, debuggee, process);
});
});
}
--- a/browser/devtools/webconsole/GcliCommands.jsm
+++ b/browser/devtools/webconsole/GcliCommands.jsm
@@ -224,17 +224,17 @@ gcli.addCommand({
name: "file",
type: {
name: "selection",
data: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let files = [];
if (dbg) {
- let scriptsView = dbg.debuggerWindow.DebuggerView.Scripts;
+ let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
for each (let script in scriptsView.scriptLocations) {
files.push(script);
}
}
return files;
}
},
description: gcli.lookup("breakaddlineFileDesc")
--- a/browser/devtools/webconsole/test/browser_gcli_break.js
+++ b/browser/devtools/webconsole/test/browser_gcli_break.js
@@ -68,27 +68,27 @@ function testCreateCommands() {
type("break add line");
is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR");
let pane = DebuggerUI.toggleDebugger();
pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() {
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume.
- pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
- pane.debuggerWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
+ pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
+ pane.contentWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
requisition.exec();
type("break list");
is(requisition.getStatus().toString(), "VALID", "break list is VALID");
requisition.exec();
- pane.debuggerWindow.gClient.activeThread.resume(function() {
+ pane.contentWindow.gClient.activeThread.resume(function() {
type("break del 0");
is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
requisition.exec();
closeConsole();
finishTest();
});
});
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd
@@ -12,17 +12,17 @@
<!ENTITY debuggerMenu.label "Script Debugger">
<!-- LOCALIZATION NOTE (remoteDebuggerMenu.label): This is the label for the
- application menu item that opens the remote debugger UI. -->
<!ENTITY remoteDebuggerMenu.label "Remote Debugger">
<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the
- application menu item that opens the browser debugger UI. -->
-<!ENTITY chromeDebuggerMenu.label "Browser Debugger">
+<!ENTITY chromeDebuggerMenu.label "Browser Debugger">
<!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that
- launches the debugger UI. Do not translate this one! -->
<!ENTITY debuggerMenu.commandkey "S">
<!-- LOCALIZATION NOTE (debuggerUI.closeButton): This is the label for the
- button that closes the debugger UI. -->
<!ENTITY debuggerUI.closeButton "Close">
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties
@@ -1,16 +1,40 @@
# LOCALIZATION NOTE These strings are used inside the Script Debugger
# which is available from the Web Developer sub-menu -> 'Script Debugger'.
# The correct localization of this file might be to keep it in
# English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
+# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the
+# remote debugger window.
+remoteDebuggerWindowTitle=Remote Debugger
+
+# LOCALIZATION NOTE (remoteDebuggerPromptTitle): The title displayed on the
+# debugger prompt asking for the remote host and port to connect to.
+remoteDebuggerPromptTitle=Remote Connection
+
+# LOCALIZATION NOTE (remoteDebuggerPromptMessage): The message displayed on the
+# debugger prompt asking for the remote host and port to connect to.
+remoteDebuggerPromptMessage=Enter hostname and port number (host:port)
+
+# LOCALIZATION NOTE (remoteDebuggerPromptCheck): The message displayed on the
+# debugger prompt asking if the prompt should be shown again next time.
+remoteDebuggerPromptCheck=Don't ask me again
+
+# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
+# debugger prompt asking for the remote host and port to connect to.
+remoteDebuggerReconnectMessage=Server not found. Try again? (host:port)
+
+# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
+# debugger prompt asking for the remote host and port to connect to.
+remoteDebuggerConnectionFailedMessage=Could not find a server at the specified hostname and port number.
+
# LOCALIZATION NOTE (pauseLabel): The label that is displayed on the pause
# button when the debugger is in a running state.
pauseLabel=Pause
# LOCALIZATION NOTE (resumeLabel): The label that is displayed on the pause
# button when the debugger is in a paused state.
resumeLabel=Resume
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1737,17 +1737,17 @@ richlistitem[type~="action"][actiontype=
}
.alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
- box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
+ box-shadow: inset -5px 0 ThreeDShadow;
}
/* Sidebar */
#sidebar-header > .tabs-closebutton {
margin-bottom: 0px !important;
padding: 0px 2px 0px 2px !important;
}
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -2191,17 +2191,17 @@ toolbarbutton.chevron > .toolbarbutton-m
}
.alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
list-style-image: url("chrome://global/skin/icons/loading_16.png") !important;
}
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
- box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
+ box-shadow: inset -5px 0 ThreeDShadow;
}
/* Tabstrip close button */
.tabs-closebutton {
-moz-padding-end: 4px;
list-style-image: url("chrome://global/skin/icons/close.png");
-moz-image-region: rect(0, 16px, 16px, 0);
border: none;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2081,17 +2081,17 @@ richlistitem[type~="action"][actiontype=
}
.alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon {
list-style-image: url("chrome://global/skin/icons/loading_16.png");
}
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
- box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
+ box-shadow: inset -5px 0 ThreeDShadow;
}
/* Tabstrip close button */
.tabs-closebutton {
-moz-appearance: none;
list-style-image: url("chrome://global/skin/icons/close.png");
-moz-image-region: rect(0, 16px, 16px, 0);
padding: 4px 2px;
--- a/toolkit/content/tests/chrome/test_tabbox.xul
+++ b/toolkit/content/tests/chrome/test_tabbox.xul
@@ -178,42 +178,47 @@ function test_tabpanels_State(tabpanels,
function test_tabbox_focus()
{
$("tabboxes").hidden = true;
$(document.activeElement).blur();
var tabbox = $("tabbox-nofocus");
var tab = $("tab-nofocus");
- tab.addEventListener("focus", function () {
- tab.removeEventListener("focus", arguments.callee, true);
+ when_tab_focused(tab, function () {
ok(document.activeElement, tab, "focus in tab with no focusable elements");
tabbox.selectedIndex = 0;
$("tab-nofocus-button").focus();
- tab.addEventListener("focus", function () {
- tab.removeEventListener("focus", arguments.callee, true);
+ when_tab_focused(tab, function () {
ok(document.activeElement, tab, "focus in tab with no focusable elements, but with something in another tab focused");
var textboxExtra = $("textbox-extra");
textboxExtra.addEventListener("focus", function () {
textboxExtra.removeEventListener("focus", arguments.callee, true);
ok(document.activeElement, textboxExtra, "focus in tab with focus currently in textbox that is sibling of tabs");
SimpleTest.finish();
}, true);
tabbox.selectedIndex = 0;
textboxExtra.hidden = false;
synthesizeMouseAtCenter(tab, { });
- }, true);
+ });
synthesizeMouseAtCenter(tab, { });
- }, true);
+ });
synthesizeMouseAtCenter(tab, { });
}
+function when_tab_focused(tab, callback) {
+ tab.addEventListener("focus", function onFocused() {
+ tab.removeEventListener("focus", onFocused, true);
+ SimpleTest.executeSoon(callback);
+ }, true);
+}
+
]]>
</script>
</window>
--- a/toolkit/content/widgets/tabbox.xml
+++ b/toolkit/content/widgets/tabbox.xml
@@ -786,23 +786,33 @@
<handlers>
<handler event="mousedown" button="0">
<![CDATA[
if (this.disabled)
return;
if (this != this.parentNode.selectedItem) { // Not selected yet
- // Select new tab after short delay so that PostHandleEvent() doesn't see
- // the tab as selected yet, otherwise it will focus the tab for us --
- // the CSS for tab has -moz-user-focus: normal only for selected="true".
- function setTab(tab) {
- tab.parentNode._selectNewTab(tab);
+ // Call this before setting the 'ignorefocus' attribute because this
+ // will pass on focus if the formerly selected tab was focused as well.
+ this.parentNode._selectNewTab(this);
+
+ var isTabFocused = false;
+ try {
+ isTabFocused = (document.commandDispatcher.focusedElement == this);
+ } catch (e) {}
+
+ // Set '-moz-user-focus' to 'ignore' so that PostHandleEvent() can't
+ // focus the tab; we only want tabs to be focusable by the mouse if
+ // they are already focused. After a short timeout we'll reset
+ // '-moz-user-focus' so that tabs can be focused by keyboard again.
+ if (!isTabFocused) {
+ this.setAttribute("ignorefocus", "true");
+ setTimeout(function (tab) tab.removeAttribute("ignorefocus"), 0, this);
}
- setTimeout(setTab, 0, this);
}
// Otherwise this tab is already selected and we will fall
// through to mousedown behavior which sets focus on the current tab,
// Only a click on an already selected tab should focus the tab itself.
]]>
</handler>
<handler event="keypress" keycode="VK_LEFT">
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -647,17 +647,17 @@ tabs {
}
tab {
-moz-binding: url("chrome://global/content/bindings/tabbox.xml#tab");
-moz-box-align: center;
-moz-box-pack: center;
}
-tab[selected="true"] {
+tab[selected="true"]:not([ignorefocus="true"]) {
-moz-user-focus: normal;
}
tabpanels {
-moz-binding: url("chrome://global/content/bindings/tabbox.xml#tabpanels");
display: -moz-deck;
}
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -42,16 +42,17 @@
* Toolkit glue for the remote debugging protocol, loaded into the
* debugging global.
*/
const Ci = Components.interfaces;
const Cc = Components.classes;
const CC = Components.Constructor;
const Cu = Components.utils;
+const Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
function dumpn(str) {