merge m-c to fx-team

This commit is contained in:
Tim Taubert 2012-09-20 11:36:34 +02:00
commit 646344e386
28 changed files with 734 additions and 374 deletions

View File

@ -38,6 +38,7 @@ DeviceRootActor.prototype = new BrowserRootActor();
* Disconnects the actor from the browser window.
*/
DeviceRootActor.prototype.disconnect = function DRA_disconnect() {
this._extraActors = null;
let actor = this._tabActors.get(this.browser);
if (actor) {
actor.exit();
@ -61,6 +62,8 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
let actorPool = new ActorPool(this.conn);
actorPool.addActor(actor);
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
// Now drop the old actorID -> actor map. Actors that still mattered were
// added to the new map, others will go away.
if (this._tabActorPool) {
@ -69,11 +72,13 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
return {
let response = {
'from': 'root',
'selected': 0,
'tabs': [actor.grip()]
};
this._appendExtraActors(response);
return response;
};
/**
@ -103,11 +108,23 @@ DeviceTabActor.prototype.grip = function DTA_grip() {
'grip() should not be called on exited browser actor.');
dbg_assert(this.actorID,
'tab should have an actorID.');
return {
let response = {
'actor': this.actorID,
'title': this.browser.title,
'url': this.browser.document.documentURI
};
// Walk over tab actors added by extensions and add them to a new ActorPool.
let actorPool = new ActorPool(this.conn);
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
if (!actorPool.isEmpty()) {
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
}
this._appendExtraActors(response);
return response;
};
/**

View File

@ -154,11 +154,8 @@ XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
});
#endif
XPCOMUtils.defineLazyGetter(this, "gBrowserNewTabPreloader", function () {
let tmp = {};
Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", tmp);
return new tmp.BrowserNewTabPreloader();
});
XPCOMUtils.defineLazyModuleGetter(this, "gBrowserNewTabPreloader",
"resource://gre/modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
let gInitialPages = [
"about:blank",
@ -1409,12 +1406,6 @@ var gBrowserInit = {
gSyncUI.init();
#endif
// Don't preload new tab pages when the toolbar is hidden
// (i.e. when the current window is a popup window).
if (window.toolbar.visible) {
gBrowserNewTabPreloader.init(window);
}
gBrowserThumbnails.init();
TabView.init();
@ -1563,10 +1554,6 @@ var gBrowserInit = {
Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
if (!__lookupGetter__("gBrowserNewTabPreloader")) {
gBrowserNewTabPreloader.uninit();
}
try {
gBrowser.removeProgressListener(window.XULBrowserWindow);
gBrowser.removeTabsProgressListener(window.TabsProgressListener);

View File

@ -1067,7 +1067,12 @@
style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
<toolbar id="devtools-sidebar-toolbar"
class="devtools-toolbar"
nowindowdrag="true"/>
nowindowdrag="true">
<spacer flex="1"/>
<toolbarbutton tooltiptext="&inspectSidebarCloseButton.tooltiptext;"
class="devtools-closebutton"
command="Inspector:Sidebar"/>
</toolbar>
<deck id="devtools-sidebar-deck" flex="1"/>
</vbox>
<splitter id="social-sidebar-splitter"

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body></body>
</html>

View File

@ -46,6 +46,7 @@ browser.jar:
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
content/browser/newtab/newTab.css (content/newtab/newTab.css)
content/browser/newtab/preload.xhtml (content/newtab/preload.xhtml)
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
* content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)
content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css)

View File

@ -38,6 +38,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource:///modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserNewTabPreloader",
"resource:///modules/BrowserNewTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
"resource://pdf.js/PdfJs.jsm");
@ -345,6 +348,7 @@ BrowserGlue.prototype = {
webappsUI.init();
PageThumbs.init();
NewTabUtils.init();
BrowserNewTabPreloader.init();
SignInToWebsiteUX.init();
PdfJs.init();
@ -370,6 +374,7 @@ BrowserGlue.prototype = {
this._shutdownPlaces();
this._sanitizer.onShutdown();
PageThumbs.uninit();
BrowserNewTabPreloader.uninit();
},
// All initial windows have opened.

View File

@ -466,39 +466,12 @@ ChromeDebuggerProcess.prototype = {
*/
_initServer: function RDP__initServer() {
if (!DebuggerServer.initialized) {
DebuggerServer.init(this._allowConnection);
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.closeListener();
DebuggerServer.openListener(DebuggerPreferences.remotePort);
},
/**
* Prompt the user to accept or decline the incoming connection.
*
* @return true if the connection should be permitted, false otherwise
*/
_allowConnection: function RDP__allowConnection() {
let title = L10N.getStr("remoteIncomingPromptTitle");
let msg = L10N.getStr("remoteIncomingPromptMessage");
let disableButton = L10N.getStr("remoteIncomingPromptDisable");
let prompt = Services.prompt;
let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK +
prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL +
prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING +
prompt.BUTTON_POS_1_DEFAULT;
let result = prompt.confirmEx(null, title, msg, flags, null, null,
disableButton, null, { value: false });
if (result == 0) {
return true;
}
if (result == 2) {
DebuggerServer.closeListener();
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false);
}
return false;
},
/**
* Initializes a profile for the remote debugger process.
*/

View File

@ -20,8 +20,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \
browser_dbg_tabactor-02.js \
browser_dbg_contextactor-01.js \
browser_dbg_contextactor-02.js \
browser_dbg_globalactor-01.js \
testactors.js \
browser_dbg_nav-01.js \
browser_dbg_propertyview-01.js \

View File

@ -1,49 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added context actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function() {
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testContextActor1" }, function(aResponse) {
ok(aResponse.actor, "testContextActor1 request should return an actor.");
ok(aResponse.actor.indexOf("testone") >= 0,
"testContextActor's actorPrefix should be used.");
gClient.request({ to: aResponse.actor, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should response to requests.");
finish_test();
});
});
});
});
}
function finish_test()
{
gClient.close(function() {
removeTab(gTab1);
finish();
});
};

View File

@ -1,59 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added context actor lifetimes.
*/
var gTab1 = null;
var gTab1Actor = null;
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
get_tab();
});
}
function get_tab()
{
gTab1 = addTab(TAB1_URL, function() {
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: gTab1Actor, type: "attach" }, function(aResponse) {
gClient.request({ to: gTab1Actor, type: "testContextActor1" }, function(aResponse) {
navigate_tab(aResponse.actor);
});
});
});
});
}
function navigate_tab(aTestActor)
{
gClient.addOneTimeListener("tabNavigated", function(aEvent, aResponse) {
gClient.request({ to: aTestActor, type: "ping" }, function(aResponse) {
// TODO: Currently the client is supposed to clean up after tabNavigated
// events. We should remove this check, or even better, remove the whole
// test.
todo(aResponse.error, "noSuchActor", "testContextActor1 should have gone away with the navigation.");
finish_test();
});
});
gTab1.linkedBrowser.loadURI(TAB2_URL);
}
function finish_test()
{
gClient.close(function() {
removeTab(gTab1);
finish();
});
}

View File

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check extension-added global actor API.
*/
var gClient = null;
function test()
{
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
is(aType, "browser", "Root actor should identify itself as a browser.");
gClient.listTabs(function(aResponse) {
let globalActor = aResponse.testGlobalActor1;
ok(globalActor, "Found the test tab actor.")
ok(globalActor.indexOf("testone") >= 0,
"testTabActor's actorPrefix should be used.");
gClient.request({ to: globalActor, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should respond to requests.");
finish_test();
});
});
});
}
function finish_test()
{
gClient.close(function() {
finish();
});
}

View File

@ -24,17 +24,15 @@ function test()
function get_tab()
{
gTab1 = addTab(TAB1_URL, function () {
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
gTab1 = addTab(TAB1_URL, function() {
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
ok(aResponse.actor, "testTabActor1 request should return an actor.");
ok(aResponse.actor.indexOf("testone") >= 0,
"testTabActor's actorPrefix should be used.");
gClient.request({ to: aResponse.actor, type: "ping" }, function (aResponse) {
is(aResponse.pong, "pong", "Actor should response to requests.");
finish_test();
});
ok(aGrip.testTabActor1, "Found the test tab actor.")
ok(aGrip.testTabActor1.indexOf("testone") >= 0,
"testTabActor's actorPrefix should be used.");
gClient.request({ to: aGrip.testTabActor1, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should respond to requests.");
finish_test();
});
});
});

View File

@ -24,10 +24,14 @@ function test()
function get_tab()
{
gTab1 = addTab(TAB1_URL, function () {
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
gTab1 = addTab(TAB1_URL, function() {
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
gTab1Actor = aGrip.actor;
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
ok(aGrip.testTabActor1, "Found the test tab actor.")
ok(aGrip.testTabActor1.indexOf("testone") >= 0,
"testTabActor's actorPrefix should be used.");
gClient.request({ to: aGrip.testTabActor1, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should respond to requests.");
close_tab(aResponse.actor);
});
});
@ -37,10 +41,16 @@ function get_tab()
function close_tab(aTestActor)
{
removeTab(gTab1);
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
is(aResponse.error, "noSuchActor", "testTabActor1 should have gone away with the tab.");
try {
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
is(aResponse, undefined, "testTabActor1 didn't go away with the tab.");
finish_test();
});
} catch (e) {
is(e.message, "'ping' request packet has no destination.",
"testTabActor1 should have gone away with the tab.");
finish_test();
});
}
}
function finish_test()

View File

@ -24,6 +24,9 @@ let gEnableRemote = Services.prefs.getBoolPref("devtools.debugger.remote-enabled
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
registerCleanupFunction(function() {
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", gEnableRemote);
// Properly shut down the server to avoid memory leaks.
DebuggerServer.destroy();
});
if (!DebuggerServer.initialized) {

View File

@ -1,20 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function TestActor1(aConnection, aTab, aOnDisconnect)
function TestActor1(aConnection, aTab)
{
this.conn = aConnection;
this.tab = aTab;
this.onDisconnect = aOnDisconnect;
}
TestActor1.prototype = {
actorPrefix: "testone",
disconnect: function TA1_disconnect() {
this.onDisconnect();
},
grip: function TA1_grip() {
return { actor: this.actorID,
test: "TestActor1" };
@ -29,30 +24,8 @@ TestActor1.prototype.requestTypes = {
"ping": TestActor1.prototype.onPing
};
DebuggerServer.addTabRequest("testTabActor1", function (aTab) {
if (aTab._testTabActor1) {
return aTab._testTabActor1.grip();
}
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
delete aTab._testTabActor1;
});
aTab.tabActorPool.addActor(actor);
aTab._testTabActor1 = actor;
return actor.grip();
});
DebuggerServer.addTabRequest("testContextActor1", function (aTab, aRequest) {
if (aTab._testContextActor1) {
return aTab._testContextActor1.grip();
}
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
delete aTab._testContextActor1;
});
aTab.contextActorPool.addActor(actor);
aTab._testContextActor1 = actor;
return actor.grip();
});
DebuggerServer.removeTabActor(TestActor1);
DebuggerServer.removeGlobalActor(TestActor1);
DebuggerServer.addTabActor(TestActor1, "testTabActor1");
DebuggerServer.addGlobalActor(TestActor1, "testGlobalActor1");

View File

@ -1647,8 +1647,9 @@ InspectorStyleSidebar.prototype = {
btn.setAttribute("image", aRegObj.icon || "");
btn.setAttribute("type", "radio");
btn.setAttribute("group", "sidebar-tools");
this._toolbar.appendChild(btn);
let spacer = this._toolbar.querySelector("spacer");
this._toolbar.insertBefore(btn, spacer);
// create tool iframe
let frame = this._chromeDoc.createElement("iframe");
frame.setAttribute("flex", "1");

View File

@ -235,6 +235,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY scratchpad.keytext "F4">
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY inspectSidebarCloseButton.tooltiptext "Close sidebar">
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
<!ENTITY devToolbarMenu.label "Developer Toolbar">

View File

@ -126,19 +126,6 @@ loadingText=Loading\u2026
# %1$S=URL, %2$S=status code
loadingError=Error loading %1$S: %2$S
# LOCALIZATION NOTE (remoteIncomingPromptTitle): The title displayed on the
# dialog that prompts the user to allow the incoming connection.
remoteIncomingPromptTitle=Incoming Connection
# LOCALIZATION NOTE (remoteIncomingPromptMessage): The message displayed on the
# dialog that prompts the user to allow the incoming connection.
remoteIncomingPromptMessage=An incoming request to permit remote debugging connection was detected. A remote client can take complete control over your browser! Allow connection?
# LOCALIZATION NOTE (remoteIncomingPromptDisable): The label displayed on the
# third button in the incoming connection dialog that lets the user disable the
# remote debugger server.
remoteIncomingPromptDisable=Disable
# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the
# variables pane when there are no variables to display.
emptyVariablesText=No variables to display.

View File

@ -7,154 +7,220 @@
let EXPORTED_SYMBOLS = ["BrowserNewTabPreloader"];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const PREF_NEWTAB_URL = "browser.newtab.url";
const PREF_NEWTAB_PRELOAD = "browser.newtab.preload";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const PREF_BRANCH = "browser.newtab.";
function BrowserNewTabPreloader() {
}
let BrowserNewTabPreloader = {
init: function Preloader_init() {
Preferences.init();
BrowserNewTabPreloader.prototype = {
_url: null,
_window: null,
_browser: null,
_enabled: null,
init: function Preloader_init(aWindow) {
if (this._window) {
return;
}
this._window = aWindow;
this._enabled = Preferences.enabled;
this._url = Preferences.url;
Preferences.addObserver(this);
if (this._enabled) {
this._createBrowser();
if (Preferences.enabled) {
HiddenBrowser.create();
}
},
uninit: function Preloader_uninit() {
if (!this._window) {
return;
}
if (this._browser) {
this._browser.parentNode.removeChild(this._browser);
this._browser = null;
}
this._window = null;
Preferences.removeObserver(this);
HostFrame.destroy();
Preferences.uninit();
HiddenBrowser.destroy();
},
newTab: function Preloader_newTab(aTab) {
if (!this._window || !this._enabled) {
return;
}
let tabbrowser = this._window.gBrowser;
if (tabbrowser && this._isPreloaded()) {
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
}
},
observe: function Preloader_observe(aEnabled, aURL) {
if (this._url != aURL) {
this._url = aURL;
if (this._enabled && aEnabled) {
// We're still enabled but the newtab URL has changed.
this._browser.setAttribute("src", aURL);
return;
}
}
if (this._enabled && !aEnabled) {
// We got disabled. Remove the browser.
this._browser.parentNode.removeChild(this._browser);
this._browser = null;
this._enabled = false;
} else if (!this._enabled && aEnabled) {
// We got enabled. Create a browser and start preloading.
this._createBrowser();
this._enabled = true;
}
},
_createBrowser: function Preloader_createBrowser() {
let document = this._window.document;
this._browser = document.createElement("browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", this._url);
this._browser.collapsed = true;
let panel = document.getElementById("browser-panel");
panel.appendChild(this._browser);
},
_isPreloaded: function Preloader_isPreloaded() {
return this._browser &&
this._browser.contentDocument &&
this._browser.contentDocument.readyState == "complete" &&
this._browser.currentURI.spec == this._url;
HiddenBrowser.swapWithNewTab(aTab);
}
};
let Preferences = {
_observers: [],
Object.freeze(BrowserNewTabPreloader);
get _branch() {
delete this._branch;
return this._branch = Services.prefs.getBranch("browser.newtab.");
},
let Preferences = {
_enabled: null,
_branch: null,
_url: null,
get enabled() {
if (!this._branch.getBoolPref("preload")) {
return false;
if (this._enabled === null) {
this._enabled = this._branch.getBoolPref("preload") &&
!this._branch.prefHasUserValue("url") &&
this.url && this.url != "about:blank";
}
if (this._branch.prefHasUserValue("url")) {
return false;
}
let url = this.url;
return url && url != "about:blank";
return this._enabled;
},
get url() {
return this._branch.getCharPref("url");
},
addObserver: function Preferences_addObserver(aObserver) {
let index = this._observers.indexOf(aObserver);
if (index == -1) {
if (this._observers.length == 0) {
this._branch.addObserver("", this, false);
}
this._observers.push(aObserver);
if (this._url === null) {
this._url = this._branch.getCharPref("url");
}
return this._url;
},
removeObserver: function Preferences_removeObserver(aObserver) {
let index = this._observers.indexOf(aObserver);
if (index > -1) {
if (this._observers.length == 1) {
this._branch.removeObserver("", this);
}
this._observers.splice(index, 1);
init: function Preferences_init() {
this._branch = Services.prefs.getBranch(PREF_BRANCH);
this._branch.addObserver("", this, false);
},
uninit: function Preferences_uninit() {
if (this._branch) {
this._branch.removeObserver("", this);
this._branch = null;
}
},
observe: function Preferences_observe(aSubject, aTopic, aData) {
let url = this.url;
let enabled = this.enabled;
let {url, enabled} = this;
this._url = this._enabled = null;
for (let obs of this._observers) {
obs.observe(enabled, url);
if (enabled && !this.enabled) {
HiddenBrowser.destroy();
} else if (!enabled && this.enabled) {
HiddenBrowser.create();
} else if (this._browser && url != this.url) {
HiddenBrowser.update(this.url);
}
},
};
let HiddenBrowser = {
get isPreloaded() {
return this._browser &&
this._browser.contentDocument &&
this._browser.contentDocument.readyState == "complete" &&
this._browser.currentURI.spec == Preferences.url;
},
swapWithNewTab: function HiddenBrowser_swapWithNewTab(aTab) {
if (this.isPreloaded) {
let tabbrowser = aTab.ownerDocument.defaultView.gBrowser;
if (tabbrowser) {
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
}
}
},
create: function HiddenBrowser_create() {
HostFrame.getFrame(function (aFrame) {
let doc = aFrame.document;
this._browser = doc.createElementNS(XUL_NS, "browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", Preferences.url);
doc.documentElement.appendChild(this._browser);
}.bind(this));
},
update: function HiddenBrowser_update(aURL) {
this._browser.setAttribute("src", aURL);
},
destroy: function HiddenBrowser_destroy() {
if (this._browser) {
this._browser.parentNode.removeChild(this._browser);
this._browser = null;
}
}
};
let HostFrame = {
_listener: null,
_privilegedFrame: null,
_privilegedContentTypes: {
"application/vnd.mozilla.xul+xml": true,
"application/xhtml+xml": true
},
get _frame() {
delete this._frame;
return this._frame = Services.appShell.hiddenDOMWindow;
},
get _isReady() {
let readyState = this._frame.document.readyState;
return (readyState == "complete" || readyState == "interactive");
},
get _isPrivileged() {
return (this._frame.location.protocol == "chrome:" &&
this._frame.document.contentType in this._privilegedContentTypes);
},
getFrame: function HostFrame_getFrame(aCallback) {
if (this._isReady && !this._isPrivileged) {
this._createPrivilegedFrame();
}
if (this._isReady) {
aCallback(this._frame);
} else {
this._waitUntilLoaded(aCallback);
}
},
destroy: function HostFrame_destroy() {
delete this._frame;
this._listener = null;
},
_createPrivilegedFrame: function HostFrame_createPrivilegedFrame() {
let doc = this._frame.document;
let iframe = doc.createElement("iframe");
iframe.setAttribute("src", "chrome://browser/content/newtab/preload.xhtml");
doc.documentElement.appendChild(iframe);
this._frame = iframe.contentWindow;
},
_waitUntilLoaded: function HostFrame_waitUntilLoaded(aCallback) {
this._listener = new HiddenWindowLoadListener(this._frame, function () {
HostFrame.getFrame(aCallback);
});
}
};
function HiddenWindowLoadListener(aWindow, aCallback) {
this._window = aWindow;
this._callback = aCallback;
let docShell = Services.appShell.hiddenWindow.docShell;
this._webProgress = docShell.QueryInterface(Ci.nsIWebProgress);
this._webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_ALL);
}
HiddenWindowLoadListener.prototype = {
_window: null,
_callback: null,
_webProgress: null,
_destroy: function HiddenWindowLoadListener_destroy() {
this._webProgress.removeProgressListener(this);
this._window = null;
this._callback = null;
this._webProgress = null;
},
onStateChange:
function HiddenWindowLoadListener_onStateChange(aWebProgress, aRequest,
aStateFlags, aStatus) {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW &&
this._window == aWebProgress.DOMWindow) {
this._callback();
this._destroy();
}
},
onStatusChange: function () {},
onLocationChange: function () {},
onProgressChange: function () {},
onSecurityChange: function () {},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
};

View File

@ -43,7 +43,7 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
// an ActorPool.
let actorPool = new ActorPool(this.conn);
let actorList = [];
let tabActorList = [];
let win = windowMediator.getMostRecentWindow("navigator:browser");
this.browser = win.BrowserApp.selectedBrowser;
@ -59,7 +59,7 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
let browser = tab.browser;
if (browser == this.browser) {
selected = actorList.length;
selected = tabActorList.length;
}
let actor = this._tabActors.get(browser);
@ -70,9 +70,11 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
}
actorPool.addActor(actor);
actorList.push(actor);
tabActorList.push(actor);
}
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
// Now drop the old actorID -> actor map. Actors that still
// mattered were added to the new map, others will go
// away.
@ -83,10 +85,13 @@ DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() {
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
return { "from": "root",
"selected": selected,
"tabs": [actor.grip()
for each (actor in actorList)] };
let response = {
"from": "root",
"selected": selected,
"tabs": [actor.grip() for (actor of tabActorList)]
};
this._appendExtraActors(response);
return response;
};
/**

View File

@ -166,7 +166,8 @@ const ThreadStateTypes = {
const UnsolicitedNotifications = {
"newScript": "newScript",
"tabDetached": "tabDetached",
"tabNavigated": "tabNavigated"
"tabNavigated": "tabNavigated",
"profilerStateChanged": "profilerStateChanged"
};
/**

View File

@ -31,20 +31,24 @@ function BrowserRootActor(aConnection)
this.conn = aConnection;
this._tabActors = new WeakMap();
this._tabActorPool = null;
this._actorFactories = null;
// A map of actor names to actor instances provided by extensions.
this._extraActors = {};
this.onTabClosed = this.onTabClosed.bind(this);
windowMediator.addListener(this);
}
BrowserRootActor.prototype = {
/**
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
*/
sayHello: function BRA_sayHello() {
return { from: "root",
applicationType: "browser",
traits: [] };
return {
from: "root",
applicationType: "browser",
traits: {}
};
},
/**
@ -52,6 +56,7 @@ BrowserRootActor.prototype = {
*/
disconnect: function BRA_disconnect() {
windowMediator.removeListener(this);
this._extraActors = null;
// We may have registered event listeners on browser windows to
// watch for tab closes, remove those.
@ -77,7 +82,7 @@ BrowserRootActor.prototype = {
// an ActorPool.
let actorPool = new ActorPool(this.conn);
let actorList = [];
let tabActorList = [];
// Walk over open browser windows.
let e = windowMediator.getEnumerator("navigator:browser");
@ -95,7 +100,7 @@ BrowserRootActor.prototype = {
let browsers = win.getBrowser().browsers;
for each (let browser in browsers) {
if (browser == selectedBrowser && win == top) {
selected = actorList.length;
selected = tabActorList.length;
}
let actor = this._tabActors.get(browser);
if (!actor) {
@ -104,10 +109,12 @@ BrowserRootActor.prototype = {
this._tabActors.set(browser, actor);
}
actorPool.addActor(actor);
actorList.push(actor);
tabActorList.push(actor);
}
}
this._createExtraActors(DebuggerServer.globalActorFactories, actorPool);
// Now drop the old actorID -> actor map. Actors that still
// mattered were added to the new map, others will go
// away.
@ -117,10 +124,40 @@ BrowserRootActor.prototype = {
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
return { "from": "root",
"selected": selected,
"tabs": [actor.grip()
for each (actor in actorList)] };
let response = {
"from": "root",
"selected": selected,
"tabs": [actor.grip() for (actor of tabActorList)]
};
this._appendExtraActors(response);
return response;
},
/**
* Adds dynamically-added actors from add-ons to the provided pool.
*/
_createExtraActors: function BRA_createExtraActors(aFactories, aPool) {
// Walk over global actors added by extensions.
for (let name in aFactories) {
let actor = this._extraActors[name];
if (!actor) {
actor = aFactories[name].bind(null, this.conn);
actor.prototype = aFactories[name].prototype;
actor.parentID = this.actorID;
this._extraActors[name] = actor;
}
aPool.addActor(actor);
}
},
/**
* Appends the extra actors to the specified object.
*/
_appendExtraActors: function BRA_appendExtraActors(aObject) {
for (let name in this._extraActors) {
let actor = this._extraActors[name];
aObject[name] = actor.actorID;
}
},
/**
@ -203,7 +240,12 @@ function BrowserTabActor(aConnection, aBrowser, aTabBrowser)
this.conn = aConnection;
this._browser = aBrowser;
this._tabbrowser = aTabBrowser;
this._tabActorPool = null;
// A map of actor names to actor instances provided by extensions.
this._extraActors = {};
this._createExtraActors = BrowserRootActor.prototype._createExtraActors.bind(this);
this._appendExtraActors = BrowserRootActor.prototype._appendExtraActors.bind(this);
this._onWindowCreated = this.onWindowCreated.bind(this);
}
@ -245,6 +287,7 @@ BrowserTabActor.prototype = {
this.conn.removeActor(aActor);
},
// A constant prefix that will be used to form the actor ID by the server.
actorPrefix: "tab",
grip: function BTA_grip() {
@ -252,9 +295,23 @@ BrowserTabActor.prototype = {
"grip() shouldn't be called on exited browser actor.");
dbg_assert(this.actorID,
"tab should have an actorID.");
return { actor: this.actorID,
title: this.browser.contentTitle,
url: this.browser.currentURI.spec }
let response = {
actor: this.actorID,
title: this.browser.contentTitle,
url: this.browser.currentURI.spec
};
// Walk over tab actors added by extensions and add them to a new ActorPool.
let actorPool = new ActorPool(this.conn);
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
if (!actorPool.isEmpty()) {
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
}
this._appendExtraActors(response);
return response;
},
/**
@ -266,6 +323,7 @@ BrowserTabActor.prototype = {
if (this._progressListener) {
this._progressListener.destroy();
}
this._extraActors = null;
},
/**
@ -370,6 +428,10 @@ BrowserTabActor.prototype = {
// Shut down actors that belong to this tab's pool.
this.conn.removeActorPool(this._tabPool);
this._tabPool = null;
if (this._tabActorPool) {
this.conn.removeActorPool(this._tabActorPool);
this._tabActorPool = null;
}
this._attached = false;
},
@ -535,9 +597,14 @@ DebuggerProgressListener.prototype = {
}
};
// DebuggerServer extension API.
/**
* Registers handlers for new request types defined dynamically. This is used
* for example by add-ons to augment the functionality of the tab actor.
* Registers handlers for new tab-scoped request types defined dynamically.
* This is used for example by add-ons to augment the functionality of the tab
* actor.
* TODO: remove this API in the next release after bug 753401 lands, once all
* our experimental add-ons have been converted to the new API.
*
* @param aName string
* The name of the new request type.
@ -552,3 +619,79 @@ DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
return aFunction(this, aRequest);
}
};
/**
* Registers handlers for new tab-scoped request types defined dynamically.
* This is used for example by add-ons to augment the functionality of the tab
* actor.
*
* @param aFunction function
* The constructor function for this request type.
* @param aName string [optional]
* The name of the new request type. If this is not present, the
* actorPrefix property of the constructor prototype is used.
*/
DebuggerServer.addTabActor = function DS_addTabActor(aFunction, aName) {
let name = aName ? aName : aFunction.prototype.actorPrefix;
if (["title", "url", "actor"].indexOf(name) != -1) {
throw Error(name + " is not allowed");
}
if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) {
throw Error(name + " already exists");
}
DebuggerServer.tabActorFactories[name] = aFunction;
};
/**
* Unregisters the handler for the specified tab-scoped request type.
* This may be used for example by add-ons when shutting down or upgrading.
*
* @param aFunction function
* The constructor function for this request type.
*/
DebuggerServer.removeTabActor = function DS_removeTabActor(aFunction) {
for (let name in DebuggerServer.tabActorFactories) {
let handler = DebuggerServer.tabActorFactories[name];
if (handler.name == aFunction.name) {
delete DebuggerServer.tabActorFactories[name];
}
}
};
/**
* Registers handlers for new browser-scoped request types defined dynamically.
* This is used for example by add-ons to augment the functionality of the root
* actor.
*
* @param aFunction function
* The constructor function for this request type.
* @param aName string [optional]
* The name of the new request type. If this is not present, the
* actorPrefix property of the constructor prototype is used.
*/
DebuggerServer.addGlobalActor = function DS_addGlobalActor(aFunction, aName) {
let name = aName ? aName : aFunction.prototype.actorPrefix;
if (["from", "tabs", "selected"].indexOf(name) != -1) {
throw Error(name + " is not allowed");
}
if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) {
throw Error(name + " already exists");
}
DebuggerServer.globalActorFactories[name] = aFunction;
};
/**
* Unregisters the handler for the specified browser-scoped request type.
* This may be used for example by add-ons when shutting down or upgrading.
*
* @param aFunction function
* The constructor function for this request type.
*/
DebuggerServer.removeGlobalActor = function DS_removeGlobalActor(aFunction) {
for (let name in DebuggerServer.globalActorFactories) {
let handler = DebuggerServer.globalActorFactories[name];
if (handler.name == aFunction.name) {
delete DebuggerServer.globalActorFactories[name];
}
}
};

View File

@ -0,0 +1,90 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Creates a ProfilerActor. ProfilerActor provides remote access to the
* built-in profiler module.
*/
function ProfilerActor(aConnection)
{
this._conn = aConnection;
this._profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
this._started = false;
Cu.import("resource://gre/modules/Services.jsm");
Services.obs.addObserver(this, "profiler-started", false);
Services.obs.addObserver(this, "profiler-stopped", false);
}
ProfilerActor.prototype = {
actorPrefix: "profiler",
disconnect: function() {
if (this._profiler && this._started) {
this._profiler.StopProfiler();
}
this._profiler = null;
},
onStartProfiler: function(aRequest) {
this._profiler.StartProfiler(aRequest.entries, aRequest.interval,
aRequest.features, aRequest.features.length);
this._started = true;
return { "msg": "profiler started" }
},
onStopProfiler: function(aRequest) {
this._profiler.StopProfiler();
this._started = false;
return { "msg": "profiler stopped" }
},
onGetProfileStr: function(aRequest) {
var profileStr = this._profiler.GetProfile();
return { "profileStr": profileStr }
},
onGetProfile: function(aRequest) {
var profile = this._profiler.getProfileData();
return { "profile": profile }
},
onIsActive: function(aRequest) {
var isActive = this._profiler.IsActive();
return { "isActive": isActive }
},
onGetResponsivenessTimes: function(aRequest) {
var times = this._profiler.GetResponsivenessTimes({});
return { "responsivenessTimes": times }
},
onGetFeatures: function(aRequest) {
var features = this._profiler.GetFeatures([]);
return { "features": features }
},
onGetSharedLibraryInformation: function(aRequest) {
var sharedLibraries = this._profiler.getSharedLibraryInformation();
return { "sharedLibraryInformation": sharedLibraries }
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "profiler-started") {
this.conn.send({ from: this.actorID, type: "profilerStateChanged", isActive: true });
} else if (aTopic == "profiler-stopped") {
this.conn.send({ from: this.actorID, type: "profilerStateChanged", isActive: false });
}
},
};
/**
* The request types this actor can handle.
*/
ProfilerActor.prototype.requestTypes = {
"startProfiler": ProfilerActor.prototype.onStartProfiler,
"stopProfiler": ProfilerActor.prototype.onStopProfiler,
"getProfileStr": ProfilerActor.prototype.onGetProfileStr,
"getProfile": ProfilerActor.prototype.onGetProfile,
"isActive": ProfilerActor.prototype.onIsActive,
"getResponsivenessTimes": ProfilerActor.prototype.onGetResponsivenessTimes,
"getFeatures": ProfilerActor.prototype.onGetFeatures,
"getSharedLibraryInformation": ProfilerActor.prototype.onGetSharedLibraryInformation
};
DebuggerServer.addGlobalActor(ProfilerActor, "profilerActor");

View File

@ -15,8 +15,10 @@ const Cc = Components.classes;
const CC = Components.Constructor;
const Cu = Components.utils;
const Cr = Components.results;
const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
Cu.import("resource://gre/modules/jsdebugger.jsm");
@ -59,11 +61,42 @@ var DebuggerServer = {
_listener: null,
_transportInitialized: false,
xpcInspector: null,
_allowConnection: null,
// Number of currently open TCP connections.
_socketConnections: 0,
// Map of global actor names to actor constructors provided by extensions.
globalActorFactories: null,
// Map of tab actor names to actor constructors provided by extensions.
tabActorFactories: null,
LONG_STRING_LENGTH: 10000,
LONG_STRING_INITIAL_LENGTH: 1000,
/**
* Prompt the user to accept or decline the incoming connection.
*
* @return true if the connection should be permitted, false otherwise
*/
_allowConnection: function DH__allowConnection() {
let title = L10N.getStr("remoteIncomingPromptTitle");
let msg = L10N.getStr("remoteIncomingPromptMessage");
let disableButton = L10N.getStr("remoteIncomingPromptDisable");
let prompt = Services.prompt;
let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK +
prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL +
prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING +
prompt.BUTTON_POS_1_DEFAULT;
let result = prompt.confirmEx(null, title, msg, flags, null, null,
disableButton, null, { value: false });
if (result == 0) {
return true;
}
if (result == 2) {
DebuggerServer.closeListener(true);
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false);
}
return false;
},
/**
* Initialize the debugger server.
*
@ -79,6 +112,9 @@ var DebuggerServer = {
this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
this.initTransport(aAllowConnectionCallback);
this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
this.globalActorFactories = {};
this.tabActorFactories = {};
},
/**
@ -97,10 +133,27 @@ var DebuggerServer = {
this._connections = {};
this._nextConnID = 0;
this._transportInitialized = true;
this._allowConnection = aAllowConnectionCallback;
if (aAllowConnectionCallback) {
this._allowConnection = aAllowConnectionCallback;
}
},
get initialized() { return !!this.xpcInspector; },
get initialized() { return !!this.globalActorFactories; },
/**
* Performs cleanup tasks before shutting down the debugger server, if no
* connections are currently open. Such tasks include clearing any actor
* constructors added at runtime. This method should be called whenever a
* debugger server is no longer useful, to avoid memory leaks. After this
* method returns, the debugger server must be initialized again before use.
*/
destroy: function DH_destroy() {
if (Object.keys(this._connections).length == 0) {
dumpn("Shutting down debugger server.");
delete this.globalActorFactories;
delete this.tabActorFactories;
}
},
/**
* Load a subscript into the debugging global.
@ -119,6 +172,8 @@ var DebuggerServer = {
*/
addBrowserActors: function DH_addBrowserActors() {
this.addActors("chrome://global/content/devtools/dbg-browser-actors.js");
if ("nsIProfiler" in Ci)
this.addActors("chrome://global/content/devtools/dbg-profiler-actors.js");
},
/**
@ -133,8 +188,9 @@ var DebuggerServer = {
}
this._checkInit();
// Return early if the server is already listening.
if (this._listener) {
throw "Debugging listener already open.";
return true;
}
let localOnly = false;
@ -151,22 +207,32 @@ var DebuggerServer = {
dumpn("Could not start debugging listener on port " + aPort + ": " + e);
throw Cr.NS_ERROR_NOT_AVAILABLE;
}
this._socketConnections++;
return true;
},
/**
* Close a previously-opened TCP listener.
*
* @param aForce boolean [optional]
* If set to true, then the socket will be closed, regardless of the
* number of open connections.
*/
closeListener: function DH_closeListener() {
closeListener: function DH_closeListener(aForce) {
this._checkInit();
if (!this._listener) {
if (!this._listener || this._socketConnections == 0) {
return false;
}
this._listener.close();
this._listener = null;
// Only close the listener when the last connection is closed, or if the
// aForce flag is passed.
if (--this._socketConnections == 0 || aForce) {
this._listener.close();
this._listener = null;
this._socketConnections = 0;
}
return true;
},
@ -197,6 +263,9 @@ var DebuggerServer = {
// nsIServerSocketListener implementation
onSocketAccepted: function DH_onSocketAccepted(aSocket, aTransport) {
if (!this._allowConnection()) {
return;
}
dumpn("New debugging connection on " + aTransport.host + ":" + aTransport.port);
try {
@ -229,9 +298,6 @@ var DebuggerServer = {
* after connectPipe() or after an incoming socket connection.
*/
_onConnection: function DH_onConnection(aTransport) {
if (!this._allowConnection()) {
return;
}
let connID = "conn" + this._nextConnID++ + '.';
let conn = new DebuggerServerConnection(connID, aTransport);
this._connections[connID] = conn;
@ -244,10 +310,12 @@ var DebuggerServer = {
},
/**
* Remove the connection from the debugging server.
* Remove the connection from the debugging server and shut down the server
* if no other connections are open.
*/
_connectionClosed: function DH_connectionClosed(aConnection) {
delete this._connections[aConnection.prefix];
this.destroy();
}
};
@ -278,7 +346,11 @@ ActorPool.prototype = {
addActor: function AP_addActor(aActor) {
aActor.conn = this.conn;
if (!aActor.actorID) {
aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
let prefix = aActor.actorPrefix;
if (typeof aActor == "function") {
prefix = aActor.prototype.actorPrefix;
}
aActor.actorID = this.conn.allocID(prefix || undefined);
}
if (aActor.registeredPool) {
@ -300,6 +372,13 @@ ActorPool.prototype = {
return aActorID in this._actors;
},
/**
* Returns true if the pool is empty.
*/
isEmpty: function AP_isEmpty() {
return Object.keys(this._actors).length == 0;
},
/**
* Remove an actor from the actor pool.
*/
@ -437,6 +516,24 @@ DebuggerServerConnection.prototype = {
return;
}
// Dyamically-loaded actors have to be created lazily.
if (typeof actor == "function") {
let instance;
try {
instance = new actor();
} catch (e) {
Cu.reportError(e);
this.transport.send({
error: "unknownError",
message: ("error occurred while creating actor '" + actor.name +
"': " + safeErrorString(e))
});
}
actor.registeredPool.addActor(instance);
actor.registeredPool.removeActor(actor);
actor = instance;
}
var ret = null;
// Dispatch the request to the actor.
@ -487,3 +584,23 @@ DebuggerServerConnection.prototype = {
DebuggerServer._connectionClosed(this);
}
};
/**
* 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);
});

View File

@ -27,7 +27,12 @@ function really_long() {
function test_socket_conn()
{
DebuggerServer.openListener(2929);
do_check_eq(DebuggerServer._socketConnections, 0);
do_check_true(DebuggerServer.openListener(2929));
do_check_eq(DebuggerServer._socketConnections, 1);
// Make sure opening the listener twice does nothing.
do_check_true(DebuggerServer.openListener(2929));
do_check_eq(DebuggerServer._socketConnections, 1);
let unicodeString = "(╯°□°)╯︵ ┻━┻";
let transport = debuggerSocketConnect("127.0.0.1", 2929);
@ -54,7 +59,12 @@ function test_socket_conn()
function test_socket_shutdown()
{
DebuggerServer.closeListener();
do_check_eq(DebuggerServer._socketConnections, 1);
do_check_true(DebuggerServer.closeListener());
do_check_eq(DebuggerServer._socketConnections, 0);
// Make sure closing the listener twice does nothing.
do_check_false(DebuggerServer.closeListener());
do_check_eq(DebuggerServer._socketConnections, 0);
let transport = debuggerSocketConnect("127.0.0.1", 2929);
transport.hooks = {

View File

@ -7,3 +7,4 @@ toolkit.jar:
content/global/devtools/dbg-server.js (debugger/server/dbg-server.js)
content/global/devtools/dbg-script-actors.js (debugger/server/dbg-script-actors.js)
content/global/devtools/dbg-browser-actors.js (debugger/server/dbg-browser-actors.js)
content/global/devtools/dbg-profiler-actors.js (debugger/server/dbg-profiler-actors.js)

View File

@ -0,0 +1,24 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE These strings are used inside the Debugger
# which is available from the Web Developer sub-menu -> '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 (remoteIncomingPromptTitle): The title displayed on the
# dialog that prompts the user to allow the incoming connection.
remoteIncomingPromptTitle=Incoming Connection
# LOCALIZATION NOTE (remoteIncomingPromptMessage): The message displayed on the
# dialog that prompts the user to allow the incoming connection.
remoteIncomingPromptMessage=An incoming request to permit remote debugging connection was detected. A remote client can take complete control over your browser! Allow connection?
# LOCALIZATION NOTE (remoteIncomingPromptDisable): The label displayed on the
# third button in the incoming connection dialog that lets the user disable the
# remote debugger server.
remoteIncomingPromptDisable=Disable

View File

@ -29,6 +29,7 @@
locale/@AB_CD@/global/customizeToolbar.properties (%chrome/global/customizeToolbar.properties)
locale/@AB_CD@/global/datetimepicker.dtd (%chrome/global/datetimepicker.dtd)
locale/@AB_CD@/global/dateFormat.properties (%chrome/global/dateFormat.properties)
locale/@AB_CD@/global/devtools/debugger.properties (%chrome/global/devtools/debugger.properties)
locale/@AB_CD@/global/dialogOverlay.dtd (%chrome/global/dialogOverlay.dtd)
locale/@AB_CD@/global/downloadProgress.properties (%chrome/global/downloadProgress.properties)
locale/@AB_CD@/global/editMenuOverlay.dtd (%chrome/global/editMenuOverlay.dtd)