Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2012-05-08 11:57:02 +01:00
commit 04b525fbdc
46 changed files with 575 additions and 144 deletions

View File

@ -1055,6 +1055,9 @@ 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);

View File

@ -46,6 +46,7 @@ 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");
@ -82,24 +83,22 @@ DebuggerUI.prototype = {
},
/**
* 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;
@ -108,17 +107,35 @@ DebuggerUI.prototype = {
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
@ -131,12 +148,14 @@ DebuggerUI.prototype = {
/**
* 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();
}
@ -181,7 +200,7 @@ DebuggerPane.prototype = {
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;
@ -216,7 +235,7 @@ DebuggerPane.prototype = {
* 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;
},
@ -225,38 +244,115 @@ DebuggerPane.prototype = {
* @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.
@ -293,7 +389,7 @@ DebuggerProcess.prototype = {
* 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"
@ -323,7 +419,7 @@ DebuggerProcess.prototype = {
if (!this._win) {
return;
}
delete this._win._remoteDebugger;
delete this._win._chromeDebugger;
this._win = null;
if (this._dbgProcess.isRunning) {
@ -341,6 +437,26 @@ DebuggerProcess.prototype = {
}
};
/**
* 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.
*/

View File

@ -87,6 +87,7 @@ let DebuggerController = {
DebuggerView.StackFrames.initialize();
DebuggerView.Properties.initialize();
DebuggerView.Scripts.initialize();
DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
this.dispatchEvent("Debugger:Loaded");
this._connect();
@ -114,7 +115,48 @@ let DebuggerController = {
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;
},
/**
@ -122,9 +164,15 @@ let DebuggerController = {
* 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);
@ -223,8 +271,16 @@ let DebuggerController = {
* 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;
},
/**
@ -1325,7 +1381,29 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
/**
* 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.
@ -1343,6 +1421,22 @@ 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.
*/

View File

@ -82,6 +82,61 @@ let DebuggerView = {
*/
_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) { }
}
}
};

View File

@ -75,7 +75,7 @@
<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>

View File

@ -47,6 +47,7 @@ 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 \

View File

@ -30,7 +30,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

View File

@ -28,7 +28,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

View File

@ -15,7 +15,7 @@ function test() {
debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testCleanExit();
});

View File

@ -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;
});

View File

@ -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() {
info("process location: " + gProcess._dbgProcess.location);
info("process pid: " + gProcess._dbgProcess.pid);
info("process name: " + gProcess._dbgProcess.processName);
info("process sig: " + gProcess._dbgProcess.processSignature);
let frames = gDebugger.DebuggerView.StackFrames._frames;
let childNodes = frames.childNodes;
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(gDebugger.DebuggerController.activeThread.paused, true,
"Should be paused after an interrupt request.");
info("profile localDir: " + gProcess._dbgProfile.localDir);
info("profile rootDir: " + gProcess._dbgProfile.rootDir);
info("profile name: " + gProcess._dbgProfile.name);
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
"Should have one frame in the stack.");
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];
DebuggerUI.toggleRemoteDebugger();
}}, 0);
}
is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
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.");
iframe.runDebuggerStatement();
},
function beforeTabAdded() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.closeListener();
info("process exit value: " + gProcess._dbgProcess.exitValue);
gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
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;
});

View File

@ -15,7 +15,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testAnonCall();
});

View File

@ -14,7 +14,10 @@ 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.");

View File

@ -17,7 +17,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -12,7 +12,7 @@ function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testPause();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});
@ -25,6 +25,9 @@ function testSimpleCall() {
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");
@ -79,10 +82,18 @@ function testSimpleCall() {
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.");

View File

@ -17,7 +17,7 @@ function test()
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testFrameParameters();
});

View File

@ -17,7 +17,7 @@ function test()
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testFrameParameters();
});

View File

@ -25,7 +25,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

View File

@ -20,7 +20,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

View File

@ -22,7 +22,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

View File

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -24,7 +24,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSelectLine();
});

View File

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

View File

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testEvalCall();
});

View File

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testRecurse();
});

View File

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testEvalCallResume();
});

View File

@ -22,7 +22,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

View File

@ -29,7 +29,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

View File

@ -49,12 +49,16 @@ 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) {
@ -99,20 +103,41 @@ function debug_tab_pane(aURL, aOnDebugging)
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);

View File

@ -229,7 +229,7 @@ gcli.addCommand({
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);
}

View File

@ -73,8 +73,8 @@ function testCreateCommands() {
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();
@ -83,7 +83,7 @@ function testCreateCommands() {
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();

View File

@ -17,7 +17,7 @@
<!-- 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! -->

View File

@ -6,6 +6,30 @@
# 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

View File

@ -1742,7 +1742,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
.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 */

View File

@ -2196,7 +2196,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
.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 */

View File

@ -2086,7 +2086,7 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
.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 */

View File

@ -183,15 +183,13 @@ function test_tabbox_focus()
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");
@ -205,14 +203,21 @@ function test_tabbox_focus()
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>

View File

@ -791,13 +791,23 @@
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,

View File

@ -652,7 +652,7 @@ tab {
-moz-box-pack: center;
}
tab[selected="true"] {
tab[selected="true"]:not([ignorefocus="true"]) {
-moz-user-focus: normal;
}

View File

@ -47,6 +47,7 @@ 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");