зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1059308 - Make frame selection button to work in browser toolbox. r=jryans,past
This commit is contained in:
Родитель
2b002a6748
Коммит
69947869b3
|
@ -178,6 +178,11 @@ let RemoteDebugger = {
|
||||||
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
|
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
|
||||||
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
|
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
|
||||||
|
|
||||||
|
// Allow debugging of chrome for any process
|
||||||
|
if (!restrictPrivileges) {
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a root actor appropriate for use in a server running in B2G.
|
* Construct a root actor appropriate for use in a server running in B2G.
|
||||||
* The returned root actor respects the factories registered with
|
* The returned root actor respects the factories registered with
|
||||||
|
|
|
@ -110,6 +110,7 @@ devtoolsCommandlineHandler.prototype = {
|
||||||
let debuggerServer = serverLoader.DebuggerServer;
|
let debuggerServer = serverLoader.DebuggerServer;
|
||||||
debuggerServer.init();
|
debuggerServer.init();
|
||||||
debuggerServer.addBrowserActors();
|
debuggerServer.addBrowserActors();
|
||||||
|
debuggerServer.allowChromeProcess = true;
|
||||||
|
|
||||||
let listener = debuggerServer.createListener();
|
let listener = debuggerServer.createListener();
|
||||||
listener.portOrPath = portOrPath;
|
listener.portOrPath = portOrPath;
|
||||||
|
|
|
@ -116,29 +116,31 @@ BrowserToolboxProcess.prototype = {
|
||||||
* Initializes the debugger server.
|
* Initializes the debugger server.
|
||||||
*/
|
*/
|
||||||
_initServer: function() {
|
_initServer: function() {
|
||||||
|
if (this.debuggerServer) {
|
||||||
|
dumpn("The chrome toolbox server is already running.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dumpn("Initializing the chrome toolbox server.");
|
dumpn("Initializing the chrome toolbox server.");
|
||||||
|
|
||||||
if (!this.loader) {
|
// Create a separate loader instance, so that we can be sure to receive a
|
||||||
// Create a separate loader instance, so that we can be sure to receive a
|
// separate instance of the DebuggingServer from the rest of the devtools.
|
||||||
// separate instance of the DebuggingServer from the rest of the devtools.
|
// This allows us to safely use the tools against even the actors and
|
||||||
// This allows us to safely use the tools against even the actors and
|
// DebuggingServer itself, especially since we can mark this loader as
|
||||||
// DebuggingServer itself, especially since we can mark this loader as
|
// invisible to the debugger (unlike the usual loader settings).
|
||||||
// invisible to the debugger (unlike the usual loader settings).
|
this.loader = new DevToolsLoader();
|
||||||
this.loader = new DevToolsLoader();
|
this.loader.invisibleToDebugger = true;
|
||||||
this.loader.invisibleToDebugger = true;
|
this.loader.main("devtools/server/main");
|
||||||
this.loader.main("devtools/server/main");
|
this.debuggerServer = this.loader.DebuggerServer;
|
||||||
this.debuggerServer = this.loader.DebuggerServer;
|
dumpn("Created a separate loader instance for the DebuggerServer.");
|
||||||
dumpn("Created a separate loader instance for the DebuggerServer.");
|
|
||||||
|
|
||||||
// Forward interesting events.
|
// Forward interesting events.
|
||||||
this.debuggerServer.on("connectionchange", this.emit.bind(this));
|
this.debuggerServer.on("connectionchange", this.emit.bind(this));
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.debuggerServer.initialized) {
|
this.debuggerServer.init();
|
||||||
this.debuggerServer.init();
|
this.debuggerServer.addBrowserActors();
|
||||||
this.debuggerServer.addBrowserActors();
|
this.debuggerServer.allowChromeProcess = true;
|
||||||
dumpn("initialized and added the browser actors for the DebuggerServer.");
|
dumpn("initialized and added the browser actors for the DebuggerServer.");
|
||||||
}
|
|
||||||
|
|
||||||
let chromeDebuggingPort =
|
let chromeDebuggingPort =
|
||||||
Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port");
|
Services.prefs.getIntPref("devtools.debugger.chrome-debugging-port");
|
||||||
|
|
|
@ -129,11 +129,19 @@ let onConnectionReady = Task.async(function*(aType, aTraits) {
|
||||||
let gParent = document.getElementById("globalActors");
|
let gParent = document.getElementById("globalActors");
|
||||||
|
|
||||||
// Build the Remote Process button
|
// Build the Remote Process button
|
||||||
if (Object.keys(globals).length > 1) {
|
// If Fx<37, tab actors were used to be exposed on RootActor
|
||||||
|
// but in Fx>=37, chrome is debuggable via attachProcess() and ChromeActor
|
||||||
|
if (globals.consoleActor || gClient.mainRoot.traits.allowChromeProcess) {
|
||||||
let a = document.createElement("a");
|
let a = document.createElement("a");
|
||||||
a.onclick = function() {
|
a.onclick = function() {
|
||||||
openToolbox(globals, true);
|
if (gClient.mainRoot.traits.allowChromeProcess) {
|
||||||
|
gClient.attachProcess()
|
||||||
|
.then(aResponse => {
|
||||||
|
openToolbox(aResponse.form, true);
|
||||||
|
});
|
||||||
|
} else if (globals.consoleActor) {
|
||||||
|
openToolbox(globals, true, "webconsole", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
a.title = a.textContent = window.l10n.GetStringFromName("mainProcess");
|
a.title = a.textContent = window.l10n.GetStringFromName("mainProcess");
|
||||||
a.className = "remote-process";
|
a.className = "remote-process";
|
||||||
|
|
|
@ -697,6 +697,7 @@ let gDevToolsBrowser = {
|
||||||
DebuggerServer.init();
|
DebuggerServer.init();
|
||||||
DebuggerServer.addBrowserActors();
|
DebuggerServer.addBrowserActors();
|
||||||
}
|
}
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
|
|
||||||
let transport = DebuggerServer.connectPipe();
|
let transport = DebuggerServer.connectPipe();
|
||||||
let client = new DebuggerClient(transport);
|
let client = new DebuggerClient(transport);
|
||||||
|
|
|
@ -41,7 +41,9 @@ let connect = Task.async(function*() {
|
||||||
openToolbox({ form: addonActor, chrome: true, isTabActor: false });
|
openToolbox({ form: addonActor, chrome: true, isTabActor: false });
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
gClient.listTabs(openToolbox);
|
gClient.attachProcess().then(aResponse => {
|
||||||
|
openToolbox({ form: aResponse.form, chrome: true });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -52,6 +54,7 @@ function setPrefDefaults() {
|
||||||
Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
|
Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
|
||||||
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", false);
|
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", false);
|
||||||
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
|
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
|
||||||
|
Services.prefs.setBoolPref("browser.dom.window.dump.enabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", function() {
|
window.addEventListener("load", function() {
|
||||||
|
|
|
@ -2152,16 +2152,17 @@ ScratchpadWindow.prototype = Heritage.extend(ScratchpadTab.prototype, {
|
||||||
DebuggerServer.init();
|
DebuggerServer.init();
|
||||||
DebuggerServer.addBrowserActors();
|
DebuggerServer.addBrowserActors();
|
||||||
}
|
}
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
|
|
||||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
client.connect(() => {
|
client.connect(() => {
|
||||||
client.listTabs(aResponse => {
|
client.attachProcess().then(aResponse => {
|
||||||
if (aResponse.error) {
|
if (aResponse.error) {
|
||||||
reportError("listTabs", aResponse);
|
reportError("listTabs", aResponse);
|
||||||
deferred.reject(aResponse);
|
deferred.reject(aResponse);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deferred.resolve({ form: aResponse, client: client });
|
deferred.resolve({ form: aResponse.form, client: client });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -187,22 +187,16 @@ HUD_SERVICE.prototype =
|
||||||
DebuggerServer.init();
|
DebuggerServer.init();
|
||||||
DebuggerServer.addBrowserActors();
|
DebuggerServer.addBrowserActors();
|
||||||
}
|
}
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
|
|
||||||
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
let client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
client.connect(() =>
|
client.connect(() => {
|
||||||
client.listTabs((aResponse) => {
|
client.attachProcess().then(aResponse => {
|
||||||
// Add Global Process debugging...
|
// Set chrome:false in order to attach to the target
|
||||||
let globals = Cu.cloneInto(aResponse, {});
|
// (i.e. send an `attach` request to the chrome actor)
|
||||||
delete globals.tabs;
|
deferred.resolve({ form: aResponse.form, client: client, chrome: false });
|
||||||
delete globals.selected;
|
}, deferred.reject);
|
||||||
// ...only if there are appropriate actors (a 'from' property will
|
});
|
||||||
// always be there).
|
|
||||||
if (Object.keys(globals).length > 1) {
|
|
||||||
deferred.resolve({ form: globals, client: client, chrome: true });
|
|
||||||
} else {
|
|
||||||
deferred.reject("Global console not found!");
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
@ -210,13 +204,7 @@ HUD_SERVICE.prototype =
|
||||||
let target;
|
let target;
|
||||||
function getTarget(aConnection)
|
function getTarget(aConnection)
|
||||||
{
|
{
|
||||||
let options = {
|
return devtools.TargetFactory.forRemoteTab(aConnection);
|
||||||
form: aConnection.form,
|
|
||||||
client: aConnection.client,
|
|
||||||
chrome: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return devtools.TargetFactory.forRemoteTab(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openWindow(aTarget)
|
function openWindow(aTarget)
|
||||||
|
@ -241,12 +229,12 @@ HUD_SERVICE.prototype =
|
||||||
}
|
}
|
||||||
|
|
||||||
connect().then(getTarget).then(openWindow).then((aWindow) => {
|
connect().then(getTarget).then(openWindow).then((aWindow) => {
|
||||||
this.openBrowserConsole(target, aWindow, aWindow)
|
return this.openBrowserConsole(target, aWindow, aWindow)
|
||||||
.then((aBrowserConsole) => {
|
.then((aBrowserConsole) => {
|
||||||
this._browserConsoleDefer.resolve(aBrowserConsole);
|
this._browserConsoleDefer.resolve(aBrowserConsole);
|
||||||
this._browserConsoleDefer = null;
|
this._browserConsoleDefer = null;
|
||||||
})
|
})
|
||||||
}, console.error);
|
}, console.error.bind(console));
|
||||||
|
|
||||||
return this._browserConsoleDefer.promise;
|
return this._browserConsoleDefer.promise;
|
||||||
},
|
},
|
||||||
|
@ -640,10 +628,13 @@ WebConsole.prototype = {
|
||||||
|
|
||||||
this._destroyer = promise.defer();
|
this._destroyer = promise.defer();
|
||||||
|
|
||||||
let popupset = this.mainPopupSet;
|
// The document may already be removed
|
||||||
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
|
if (this.chromeUtilsWindow && this.mainPopupSet) {
|
||||||
for (let panel of panels) {
|
let popupset = this.mainPopupSet;
|
||||||
panel.hidePopup();
|
let panels = popupset.querySelectorAll("panel[hudId=" + this.hudId + "]");
|
||||||
|
for (let panel of panels) {
|
||||||
|
panel.hidePopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let onDestroy = function WC_onDestroyUI() {
|
let onDestroy = function WC_onDestroyUI() {
|
||||||
|
|
|
@ -440,7 +440,11 @@ WebConsoleFrame.prototype = {
|
||||||
* @type boolean
|
* @type boolean
|
||||||
*/
|
*/
|
||||||
get persistLog() {
|
get persistLog() {
|
||||||
return Services.prefs.getBoolPref(PREF_PERSISTLOG);
|
// For the browser console, we receive tab navigation
|
||||||
|
// when the original top level window we attached to is closed,
|
||||||
|
// but we don't want to reset console history and just switch to
|
||||||
|
// the next available window.
|
||||||
|
return this.owner._browserConsole || Services.prefs.getBoolPref(PREF_PERSISTLOG);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3426,7 +3430,7 @@ JSTerm.prototype = {
|
||||||
|
|
||||||
let selectedNodeActor = null;
|
let selectedNodeActor = null;
|
||||||
let inspectorSelection = this.hud.owner.getInspectorSelection();
|
let inspectorSelection = this.hud.owner.getInspectorSelection();
|
||||||
if (inspectorSelection) {
|
if (inspectorSelection && inspectorSelection.nodeFront) {
|
||||||
selectedNodeActor = inspectorSelection.nodeFront.actorID;
|
selectedNodeActor = inspectorSelection.nodeFront.actorID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -941,9 +941,9 @@ let UI = {
|
||||||
this.toolboxPromise = null;
|
this.toolboxPromise = null;
|
||||||
return toolboxPromise.then(toolbox => {
|
return toolboxPromise.then(toolbox => {
|
||||||
return toolbox.destroy();
|
return toolbox.destroy();
|
||||||
}).catch(console.error)
|
}).then(null, console.error)
|
||||||
.then(() => this._closeToolboxUI())
|
.then(() => this._closeToolboxUI())
|
||||||
.catch(console.error);
|
.then(null, console.error);
|
||||||
}
|
}
|
||||||
return promise.resolve();
|
return promise.resolve();
|
||||||
},
|
},
|
||||||
|
|
|
@ -217,11 +217,25 @@ let AppManager = exports.AppManager = {
|
||||||
|
|
||||||
getTarget: function() {
|
getTarget: function() {
|
||||||
if (this.selectedProject.type == "mainProcess") {
|
if (this.selectedProject.type == "mainProcess") {
|
||||||
return devtools.TargetFactory.forRemoteTab({
|
// Fx >=37 exposes a ChromeActor to debug the main process
|
||||||
form: this._listTabsResponse,
|
if (this.connection.client.mainRoot.traits.allowChromeProcess) {
|
||||||
client: this.connection.client,
|
return this.connection.client.attachProcess()
|
||||||
chrome: true
|
.then(aResponse => {
|
||||||
});
|
return devtools.TargetFactory.forRemoteTab({
|
||||||
|
form: aResponse.form,
|
||||||
|
client: this.connection.client,
|
||||||
|
chrome: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fx <37 exposes tab actors on the root actor
|
||||||
|
return devtools.TargetFactory.forRemoteTab({
|
||||||
|
form: this._listTabsResponse,
|
||||||
|
client: this.connection.client,
|
||||||
|
chrome: true,
|
||||||
|
isTabActor: false
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selectedProject.type == "tab") {
|
if (this.selectedProject.type == "tab") {
|
||||||
|
@ -414,8 +428,12 @@ let AppManager = exports.AppManager = {
|
||||||
},
|
},
|
||||||
|
|
||||||
isMainProcessDebuggable: function() {
|
isMainProcessDebuggable: function() {
|
||||||
return this._listTabsResponse &&
|
// Fx <37 exposes chrome tab actors on RootActor
|
||||||
this._listTabsResponse.consoleActor;
|
// Fx >=37 exposes a dedicated actor via attachProcess request
|
||||||
|
return this.connection.client &&
|
||||||
|
this.connection.client.mainRoot.traits.allowChromeProcess ||
|
||||||
|
(this._listTabsResponse &&
|
||||||
|
this._listTabsResponse.consoleActor);
|
||||||
},
|
},
|
||||||
|
|
||||||
get deviceFront() {
|
get deviceFront() {
|
||||||
|
|
|
@ -575,6 +575,7 @@ let gLocalRuntime = {
|
||||||
DebuggerServer.init();
|
DebuggerServer.init();
|
||||||
DebuggerServer.addBrowserActors();
|
DebuggerServer.addBrowserActors();
|
||||||
}
|
}
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
connection.host = null; // Force Pipe transport
|
connection.host = null; // Force Pipe transport
|
||||||
connection.port = null;
|
connection.port = null;
|
||||||
connection.connect();
|
connection.connect();
|
||||||
|
|
|
@ -7416,6 +7416,7 @@ var RemoteDebugger = {
|
||||||
DebuggerServer.init();
|
DebuggerServer.init();
|
||||||
DebuggerServer.addBrowserActors();
|
DebuggerServer.addBrowserActors();
|
||||||
DebuggerServer.registerModule("resource://gre/modules/dbg-browser-actors.js");
|
DebuggerServer.registerModule("resource://gre/modules/dbg-browser-actors.js");
|
||||||
|
DebuggerServer.allowChromeProcess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pathOrPort = this._getPath();
|
let pathOrPort = this._getPath();
|
||||||
|
|
|
@ -624,14 +624,17 @@ DebuggerClient.prototype = {
|
||||||
/**
|
/**
|
||||||
* Attach to a process in order to get the form of a ChildProcessActor.
|
* Attach to a process in order to get the form of a ChildProcessActor.
|
||||||
*
|
*
|
||||||
* @param string aId
|
* @param number aId
|
||||||
* The ID for the process to attach (returned by `listProcesses`).
|
* The ID for the process to attach (returned by `listProcesses`).
|
||||||
|
* Connected to the main process if omitted, or is 0.
|
||||||
*/
|
*/
|
||||||
attachProcess: function (aId) {
|
attachProcess: function (aId) {
|
||||||
let packet = {
|
let packet = {
|
||||||
to: 'root',
|
to: "root",
|
||||||
type: 'attachProcess',
|
type: "attachProcess"
|
||||||
id: aId
|
}
|
||||||
|
if (typeof(aId) == "number") {
|
||||||
|
packet.id = aId;
|
||||||
}
|
}
|
||||||
return this.request(packet);
|
return this.request(packet);
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { Ci } = require("chrome");
|
||||||
|
const Services = require("Services");
|
||||||
|
const { DebuggerServer } = require("../main");
|
||||||
|
const { getChildDocShells, TabActor } = require("./webbrowser");
|
||||||
|
const makeDebugger = require("./utils/make-debugger");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a TabActor for debugging all the chrome content in the
|
||||||
|
* current process. Most of the implementation is inherited from TabActor.
|
||||||
|
* ChromeActor is a child of RootActor, it can be instanciated via
|
||||||
|
* RootActor.attachProcess request.
|
||||||
|
* ChromeActor exposes all tab actors via its form() request, like TabActor.
|
||||||
|
*
|
||||||
|
* History lecture:
|
||||||
|
* All tab actors used to also be registered as global actors,
|
||||||
|
* so that the root actor was also exposing tab actors for the main process.
|
||||||
|
* Tab actors ended up having RootActor as parent actor,
|
||||||
|
* but more and more features of the tab actors were relying on TabActor.
|
||||||
|
* So we are now exposing a process actor that offers the same API as TabActor
|
||||||
|
* by inheriting its functionality.
|
||||||
|
* Global actors are now only the actors that are meant to be global,
|
||||||
|
* and are no longer related to any specific scope/document.
|
||||||
|
*
|
||||||
|
* @param aConnection DebuggerServerConnection
|
||||||
|
* The connection to the client.
|
||||||
|
*/
|
||||||
|
function ChromeActor(aConnection) {
|
||||||
|
TabActor.call(this, aConnection);
|
||||||
|
|
||||||
|
// This creates a Debugger instance for chrome debugging all globals.
|
||||||
|
this.makeDebugger = makeDebugger.bind(null, {
|
||||||
|
findDebuggees: dbg => dbg.findAllGlobals(),
|
||||||
|
shouldAddNewGlobalAsDebuggee: () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ensure catching the creation of any new content docshell
|
||||||
|
this.listenForNewDocShells = true;
|
||||||
|
|
||||||
|
// Defines the default docshell selected for the tab actor
|
||||||
|
let window = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
|
||||||
|
|
||||||
|
// Default to any available top level window if there is no expected window
|
||||||
|
// (for example when we open firefox with -webide argument)
|
||||||
|
if (!window) {
|
||||||
|
window = Services.wm.getMostRecentWindow(null);
|
||||||
|
}
|
||||||
|
// On xpcshell, there is no window/docshell
|
||||||
|
let docShell = window ? window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDocShell)
|
||||||
|
: null;
|
||||||
|
Object.defineProperty(this, "docShell", {
|
||||||
|
value: docShell,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.ChromeActor = ChromeActor;
|
||||||
|
|
||||||
|
ChromeActor.prototype = Object.create(TabActor.prototype);
|
||||||
|
|
||||||
|
ChromeActor.prototype.constructor = ChromeActor;
|
||||||
|
|
||||||
|
ChromeActor.prototype.isRootActor = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for the list of all docshells in this tabActor
|
||||||
|
* @return {Array}
|
||||||
|
*/
|
||||||
|
Object.defineProperty(ChromeActor.prototype, "docShells", {
|
||||||
|
get: function () {
|
||||||
|
// Iterate over all top-level windows and all their docshells.
|
||||||
|
let docShells = [];
|
||||||
|
let e = Services.ww.getWindowEnumerator();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let window = e.getNext();
|
||||||
|
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShell);
|
||||||
|
docShells = docShells.concat(getChildDocShells(docShell));
|
||||||
|
}
|
||||||
|
|
||||||
|
return docShells;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ChromeActor.prototype.observe = function(aSubject, aTopic, aData) {
|
||||||
|
TabActor.prototype.observe.call(this, aSubject, aTopic, aData);
|
||||||
|
if (!this.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aTopic == "chrome-webnavigation-create") {
|
||||||
|
aSubject.QueryInterface(Ci.nsIDocShell);
|
||||||
|
this._onDocShellCreated(aSubject);
|
||||||
|
} else if (aTopic == "chrome-webnavigation-destroy") {
|
||||||
|
this._onDocShellDestroy(aSubject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChromeActor.prototype._attach = function() {
|
||||||
|
if (this.attached) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabActor.prototype._attach.call(this);
|
||||||
|
|
||||||
|
// Listen for any new/destroyed chrome docshell
|
||||||
|
Services.obs.addObserver(this, "chrome-webnavigation-create", false);
|
||||||
|
Services.obs.addObserver(this, "chrome-webnavigation-destroy", false);
|
||||||
|
|
||||||
|
// Iterate over all top-level windows.
|
||||||
|
let docShells = [];
|
||||||
|
let e = Services.ww.getWindowEnumerator();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let window = e.getNext();
|
||||||
|
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShell);
|
||||||
|
if (docShell == this.docShell) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this._progressListener.watch(docShell);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ChromeActor.prototype._detach = function() {
|
||||||
|
if (!this.attached) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.obs.removeObserver(this, "chrome-webnavigation-create");
|
||||||
|
Services.obs.removeObserver(this, "chrome-webnavigation-destroy");
|
||||||
|
|
||||||
|
// Iterate over all top-level windows.
|
||||||
|
let docShells = [];
|
||||||
|
let e = Services.ww.getWindowEnumerator();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let window = e.getNext();
|
||||||
|
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShell);
|
||||||
|
if (docShell == this.docShell) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this._progressListener.unwatch(docShell);
|
||||||
|
}
|
||||||
|
|
||||||
|
TabActor.prototype._detach.call(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ThreadActor hooks. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare to enter a nested event loop by disabling debuggee events.
|
||||||
|
*/
|
||||||
|
ChromeActor.prototype.preNest = function() {
|
||||||
|
// Disable events in all open windows.
|
||||||
|
let e = Services.wm.getEnumerator(null);
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let win = e.getNext();
|
||||||
|
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
windowUtils.suppressEventHandling(true);
|
||||||
|
windowUtils.suspendTimeouts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare to exit a nested event loop by enabling debuggee events.
|
||||||
|
*/
|
||||||
|
ChromeActor.prototype.postNest = function(aNestData) {
|
||||||
|
// Enable events in all open windows.
|
||||||
|
let e = Services.wm.getEnumerator(null);
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
let win = e.getNext();
|
||||||
|
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
windowUtils.resumeTimeouts();
|
||||||
|
windowUtils.suppressEventHandling(false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,9 +10,6 @@ const { Cc, Ci, Cu } = require("chrome");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
|
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
|
||||||
const { DebuggerServer } = require("devtools/server/main");
|
const { DebuggerServer } = require("devtools/server/main");
|
||||||
const makeDebugger = require("./utils/make-debugger");
|
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
|
|
||||||
|
|
||||||
loader.lazyGetter(this, "ppmm", () => {
|
loader.lazyGetter(this, "ppmm", () => {
|
||||||
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
|
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
|
||||||
|
@ -99,14 +96,10 @@ function RootActor(aConnection, aParameters) {
|
||||||
this._onAddonListChanged = this.onAddonListChanged.bind(this);
|
this._onAddonListChanged = this.onAddonListChanged.bind(this);
|
||||||
this._extraActors = {};
|
this._extraActors = {};
|
||||||
|
|
||||||
// Map of DOM stylesheets to StyleSheetActors
|
this._globalActorPool = new ActorPool(this.conn);
|
||||||
this._styleSheetActors = new Map();
|
this.conn.addActorPool(this._globalActorPool);
|
||||||
|
|
||||||
// This creates a Debugger instance for chrome debugging all globals.
|
this._chromeActor = null;
|
||||||
this.makeDebugger = makeDebugger.bind(null, {
|
|
||||||
findDebuggees: dbg => dbg.findAllGlobals(),
|
|
||||||
shouldAddNewGlobalAsDebuggee: () => true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RootActor.prototype = {
|
RootActor.prototype = {
|
||||||
|
@ -160,7 +153,16 @@ RootActor.prototype = {
|
||||||
getUsedFontFaces: true,
|
getUsedFontFaces: true,
|
||||||
// Trait added in Gecko 38, indicating that all features necessary for
|
// Trait added in Gecko 38, indicating that all features necessary for
|
||||||
// grabbing allocations from the MemoryActor are available for the performance tool
|
// grabbing allocations from the MemoryActor are available for the performance tool
|
||||||
memoryActorAllocations: true
|
memoryActorAllocations: true,
|
||||||
|
// Whether root actor exposes tab actors
|
||||||
|
// if allowChromeProcess is true, you can fetch a ChromeActor instance
|
||||||
|
// to debug chrome and any non-content ressource via attachProcess request
|
||||||
|
// if allocChromeProcess is defined, but not true, it means that root actor
|
||||||
|
// no longer expose tab actors, but also that attachProcess forbids
|
||||||
|
// exposing actors for security reasons
|
||||||
|
get allowChromeProcess() {
|
||||||
|
return DebuggerServer.allowChromeProcess;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -176,66 +178,6 @@ RootActor.prototype = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* This is true for the root actor only, used by some child actors
|
|
||||||
*/
|
|
||||||
get isRootActor() true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The (chrome) window, for use by child actors
|
|
||||||
*/
|
|
||||||
get window() isWorker ? null : Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of all windows
|
|
||||||
*/
|
|
||||||
get windows() {
|
|
||||||
return this.docShells.map(docShell => {
|
|
||||||
return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindow);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of the chrome window.
|
|
||||||
*/
|
|
||||||
get url() { return this.window ? this.window.document.location.href : null; },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The top level window's docshell
|
|
||||||
*/
|
|
||||||
get docShell() {
|
|
||||||
return this.window
|
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDocShell);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of all docshells
|
|
||||||
*/
|
|
||||||
get docShells() {
|
|
||||||
let docShellsEnum = this.docShell.getDocShellEnumerator(
|
|
||||||
Ci.nsIDocShellTreeItem.typeAll,
|
|
||||||
Ci.nsIDocShell.ENUMERATE_FORWARDS
|
|
||||||
);
|
|
||||||
|
|
||||||
let docShells = [];
|
|
||||||
while (docShellsEnum.hasMoreElements()) {
|
|
||||||
docShells.push(docShellsEnum.getNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
return docShells;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for the best nsIWebProgress for to watching this window.
|
|
||||||
*/
|
|
||||||
get webProgress() {
|
|
||||||
return this.docShell
|
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIWebProgress);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects the actor from the browser window.
|
* Disconnects the actor from the browser window.
|
||||||
*/
|
*/
|
||||||
|
@ -251,8 +193,6 @@ RootActor.prototype = {
|
||||||
this._parameters.onShutdown();
|
this._parameters.onShutdown();
|
||||||
}
|
}
|
||||||
this._extraActors = null;
|
this._extraActors = null;
|
||||||
this._styleSheetActors.clear();
|
|
||||||
this._styleSheetActors = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/* The 'listTabs' request and the 'tabListChanged' notification. */
|
/* The 'listTabs' request and the 'tabListChanged' notification. */
|
||||||
|
@ -380,13 +320,34 @@ RootActor.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
onAttachProcess: function (aRequest) {
|
onAttachProcess: function (aRequest) {
|
||||||
let mm = ppmm.getChildAt(aRequest.id);
|
if (!DebuggerServer.allowChromeProcess) {
|
||||||
if (!mm) {
|
return { error: "forbidden",
|
||||||
return { error: "noProcess",
|
message: "You are not allowed to debug chrome." };
|
||||||
message: "There is no process with id '" + aRequest.id + "'." };
|
}
|
||||||
|
if (("id" in aRequest) && typeof(aRequest.id) != "number") {
|
||||||
|
return { error: "wrongParameter",
|
||||||
|
message: "attachProcess requires a valid `id` attribute." };
|
||||||
|
}
|
||||||
|
// If the request doesn't contains id parameter or id is 0
|
||||||
|
// (id == 0, based on onListProcesses implementation)
|
||||||
|
if ((!("id" in aRequest)) || aRequest.id === 0) {
|
||||||
|
if (!this._chromeActor) {
|
||||||
|
// Create a ChromeActor for the parent process
|
||||||
|
let { ChromeActor } = require("devtools/server/actors/chrome");
|
||||||
|
this._chromeActor = new ChromeActor(this.conn);
|
||||||
|
this._globalActorPool.addActor(this._chromeActor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { form: this._chromeActor.form() };
|
||||||
|
} else {
|
||||||
|
let mm = ppmm.getChildAt(aRequest.id);
|
||||||
|
if (!mm) {
|
||||||
|
return { error: "noProcess",
|
||||||
|
message: "There is no process with id '" + aRequest.id + "'." };
|
||||||
|
}
|
||||||
|
return DebuggerServer.connectToContent(this.conn, mm)
|
||||||
|
.then(form => ({ form }));
|
||||||
}
|
}
|
||||||
return DebuggerServer.connectToContent(this.conn, mm)
|
|
||||||
.then(form => ({ form: form }));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/* This is not in the spec, but it's used by tests. */
|
/* This is not in the spec, but it's used by tests. */
|
||||||
|
@ -406,60 +367,6 @@ RootActor.prototype = {
|
||||||
_createExtraActors: createExtraActors,
|
_createExtraActors: createExtraActors,
|
||||||
_appendExtraActors: appendExtraActors,
|
_appendExtraActors: appendExtraActors,
|
||||||
|
|
||||||
/* ThreadActor hooks. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare to enter a nested event loop by disabling debuggee events.
|
|
||||||
*/
|
|
||||||
preNest: function() {
|
|
||||||
// Disable events in all open windows.
|
|
||||||
let e = Services.wm.getEnumerator(null);
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
let win = e.getNext();
|
|
||||||
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
windowUtils.suppressEventHandling(true);
|
|
||||||
windowUtils.suspendTimeouts();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare to exit a nested event loop by enabling debuggee events.
|
|
||||||
*/
|
|
||||||
postNest: function(aNestData) {
|
|
||||||
// Enable events in all open windows.
|
|
||||||
let e = Services.wm.getEnumerator(null);
|
|
||||||
while (e.hasMoreElements()) {
|
|
||||||
let win = e.getNext();
|
|
||||||
let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
windowUtils.resumeTimeouts();
|
|
||||||
windowUtils.suppressEventHandling(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create or return the StyleSheetActor for a style sheet. This method
|
|
||||||
* is here because the Style Editor and Inspector share style sheet actors.
|
|
||||||
*
|
|
||||||
* @param DOMStyleSheet styleSheet
|
|
||||||
* The style sheet to create an actor for.
|
|
||||||
* @return StyleSheetActor actor
|
|
||||||
* The actor for this style sheet.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
createStyleSheetActor: function(styleSheet) {
|
|
||||||
if (this._styleSheetActors.has(styleSheet)) {
|
|
||||||
return this._styleSheetActors.get(styleSheet);
|
|
||||||
}
|
|
||||||
let actor = new StyleSheetActor(styleSheet, this);
|
|
||||||
this._styleSheetActors.set(styleSheet, actor);
|
|
||||||
|
|
||||||
this._globalActorPool.addActor(actor);
|
|
||||||
|
|
||||||
return actor;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the extra actor (added by DebuggerServer.addGlobalActor or
|
* Remove the extra actor (added by DebuggerServer.addGlobalActor or
|
||||||
* DebuggerServer.addTabActor) name |aName|.
|
* DebuggerServer.addTabActor) name |aName|.
|
||||||
|
|
|
@ -36,6 +36,35 @@ function getWindowID(window) {
|
||||||
.currentInnerWindowID;
|
.currentInnerWindowID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDocShellChromeEventHandler(docShell) {
|
||||||
|
let handler = docShell.chromeEventHandler;
|
||||||
|
if (!handler) {
|
||||||
|
try {
|
||||||
|
// toplevel xul window's docshell doesn't have chromeEventHandler attribute
|
||||||
|
// the chrome event handler is just the global window object
|
||||||
|
handler = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
function getChildDocShells(docShell) {
|
||||||
|
let docShellsEnum = docShell.getDocShellEnumerator(
|
||||||
|
Ci.nsIDocShellTreeItem.typeAll,
|
||||||
|
Ci.nsIDocShell.ENUMERATE_FORWARDS
|
||||||
|
);
|
||||||
|
|
||||||
|
let docShells = [];
|
||||||
|
while (docShellsEnum.hasMoreElements()) {
|
||||||
|
let docShell = docShellsEnum.getNext();
|
||||||
|
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
docShells.push(docShell);
|
||||||
|
}
|
||||||
|
return docShells;
|
||||||
|
}
|
||||||
|
exports.getChildDocShells = getChildDocShells;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Browser-specific actors.
|
* Browser-specific actors.
|
||||||
*/
|
*/
|
||||||
|
@ -580,6 +609,10 @@ function TabActor(aConnection)
|
||||||
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
|
shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Flag eventually overloaded by sub classes in order to watch new docshells
|
||||||
|
// Used on b2g to catch activity frames and in chrome to list all frames
|
||||||
|
this.listenForNewDocShells = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||||
|
|
||||||
this.traits = { reconfigure: true, frames: true };
|
this.traits = { reconfigure: true, frames: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,10 +640,7 @@ TabActor.prototype = {
|
||||||
* An object on which listen for DOMWindowCreated and pageshow events.
|
* An object on which listen for DOMWindowCreated and pageshow events.
|
||||||
*/
|
*/
|
||||||
get chromeEventHandler() {
|
get chromeEventHandler() {
|
||||||
// TODO: bug 992778, fix docShell.chromeEventHandler in child processes
|
return getDocShellChromeEventHandler(this.docShell);
|
||||||
return this.docShell.chromeEventHandler ||
|
|
||||||
this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -634,29 +664,20 @@ TabActor.prototype = {
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
get docShells() {
|
get docShells() {
|
||||||
let docShellsEnum = this.docShell.getDocShellEnumerator(
|
return getChildDocShells(this.docShell);
|
||||||
Ci.nsIDocShellTreeItem.typeAll,
|
|
||||||
Ci.nsIDocShell.ENUMERATE_FORWARDS
|
|
||||||
);
|
|
||||||
|
|
||||||
let docShells = [];
|
|
||||||
while (docShellsEnum.hasMoreElements()) {
|
|
||||||
let docShell = docShellsEnum.getNext();
|
|
||||||
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIWebProgress);
|
|
||||||
docShells.push(docShell);
|
|
||||||
}
|
|
||||||
|
|
||||||
return docShells;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter for the tab content's DOM window.
|
* Getter for the tab content's DOM window.
|
||||||
*/
|
*/
|
||||||
get window() {
|
get window() {
|
||||||
return this.docShell
|
// On xpcshell, there is no document
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
if (this.docShell) {
|
||||||
.getInterface(Ci.nsIDOMWindow);
|
return this.docShell
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -761,17 +782,21 @@ TabActor.prototype = {
|
||||||
dbg_assert(this.actorID,
|
dbg_assert(this.actorID,
|
||||||
"tab should have an actorID.");
|
"tab should have an actorID.");
|
||||||
|
|
||||||
let windowUtils = this.window
|
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
|
||||||
|
|
||||||
let response = {
|
let response = {
|
||||||
actor: this.actorID,
|
actor: this.actorID
|
||||||
title: this.title,
|
|
||||||
url: this.url,
|
|
||||||
outerWindowID: windowUtils.outerWindowID
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// On xpcshell we are using tabactor even if there is no valid document.
|
||||||
|
// Actors like chrome debugger can work.
|
||||||
|
if (this.window) {
|
||||||
|
response.title = this.title;
|
||||||
|
response.url = this.url;
|
||||||
|
let windowUtils = this.window
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
response.outerWindowID = windowUtils.outerWindowID;
|
||||||
|
}
|
||||||
|
|
||||||
// Walk over tab actors added by extensions and add them to a new ActorPool.
|
// Walk over tab actors added by extensions and add them to a new ActorPool.
|
||||||
let actorPool = new ActorPool(this.conn);
|
let actorPool = new ActorPool(this.conn);
|
||||||
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
|
this._createExtraActors(DebuggerServer.tabActorFactories, actorPool);
|
||||||
|
@ -869,21 +894,24 @@ TabActor.prototype = {
|
||||||
// ... and a pool for context-lifetime actors.
|
// ... and a pool for context-lifetime actors.
|
||||||
this._pushContext();
|
this._pushContext();
|
||||||
|
|
||||||
this._progressListener = new DebuggerProgressListener(this);
|
// on xpcshell, there is no document
|
||||||
|
if (this.window) {
|
||||||
|
this._progressListener = new DebuggerProgressListener(this);
|
||||||
|
|
||||||
// Save references to the original document we attached to
|
// Save references to the original document we attached to
|
||||||
this._originalWindow = this.window;
|
this._originalWindow = this.window;
|
||||||
|
|
||||||
// Ensure replying to attach() request first
|
// Ensure replying to attach() request first
|
||||||
// before notifying about new docshells.
|
// before notifying about new docshells.
|
||||||
DevToolsUtils.executeSoon(() => this._watchDocshells());
|
DevToolsUtils.executeSoon(() => this._watchDocshells());
|
||||||
|
}
|
||||||
|
|
||||||
this._attached = true;
|
this._attached = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_watchDocshells: function BTA_watchDocshells() {
|
_watchDocshells: function BTA_watchDocshells() {
|
||||||
// In child processes, we watch all docshells living in the process.
|
// In child processes, we watch all docshells living in the process.
|
||||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
if (this.listenForNewDocShells) {
|
||||||
Services.obs.addObserver(this, "webnavigation-create", false);
|
Services.obs.addObserver(this, "webnavigation-create", false);
|
||||||
}
|
}
|
||||||
Services.obs.addObserver(this, "webnavigation-destroy", false);
|
Services.obs.addObserver(this, "webnavigation-destroy", false);
|
||||||
|
@ -927,28 +955,36 @@ TabActor.prototype = {
|
||||||
}
|
}
|
||||||
if (aTopic == "webnavigation-create") {
|
if (aTopic == "webnavigation-create") {
|
||||||
aSubject.QueryInterface(Ci.nsIDocShell);
|
aSubject.QueryInterface(Ci.nsIDocShell);
|
||||||
// webnavigation-create is fired very early during docshell construction.
|
this._onDocShellCreated(aSubject);
|
||||||
// In new root docshells within child processes, involving TabChild,
|
|
||||||
// this event is from within this call:
|
|
||||||
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
|
|
||||||
// whereas the chromeEventHandler (and most likely other stuff) is set later:
|
|
||||||
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
|
|
||||||
// So wait a tick before watching it:
|
|
||||||
DevToolsUtils.executeSoon(() => {
|
|
||||||
// In child processes, we have new root docshells,
|
|
||||||
// let's watch them and all their child docshells.
|
|
||||||
if (this._isRootDocShell(aSubject)) {
|
|
||||||
this._progressListener.watch(aSubject);
|
|
||||||
}
|
|
||||||
this._notifyDocShellsUpdate([aSubject]);
|
|
||||||
});
|
|
||||||
} else if (aTopic == "webnavigation-destroy") {
|
} else if (aTopic == "webnavigation-destroy") {
|
||||||
let webProgress = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
|
this._onDocShellDestroy(aSubject);
|
||||||
.getInterface(Ci.nsIWebProgress);
|
|
||||||
this._notifyDocShellDestroy(webProgress);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onDocShellCreated: function (docShell) {
|
||||||
|
// (chrome-)webnavigation-create is fired very early during docshell construction.
|
||||||
|
// In new root docshells within child processes, involving TabChild,
|
||||||
|
// this event is from within this call:
|
||||||
|
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
|
||||||
|
// whereas the chromeEventHandler (and most likely other stuff) is set later:
|
||||||
|
// http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
|
||||||
|
// So wait a tick before watching it:
|
||||||
|
DevToolsUtils.executeSoon(() => {
|
||||||
|
// In child processes, we have new root docshells,
|
||||||
|
// let's watch them and all their child docshells.
|
||||||
|
if (this._isRootDocShell(docShell)) {
|
||||||
|
this._progressListener.watch(docShell);
|
||||||
|
}
|
||||||
|
this._notifyDocShellsUpdate([docShell]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDocShellDestroy: function (docShell) {
|
||||||
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
this._notifyDocShellDestroy(webProgress);
|
||||||
|
},
|
||||||
|
|
||||||
_isRootDocShell: function (docShell) {
|
_isRootDocShell: function (docShell) {
|
||||||
// Root docshells like top level xul windows don't have chromeEventHandler.
|
// Root docshells like top level xul windows don't have chromeEventHandler.
|
||||||
// Root docshells in child processes have one, it is TabChildGlobal,
|
// Root docshells in child processes have one, it is TabChildGlobal,
|
||||||
|
@ -962,7 +998,9 @@ TabActor.prototype = {
|
||||||
// Convert docShell list to windows objects list being sent to the client
|
// Convert docShell list to windows objects list being sent to the client
|
||||||
_docShellsToWindows: function (docshells) {
|
_docShellsToWindows: function (docshells) {
|
||||||
return docshells.map(docShell => {
|
return docshells.map(docShell => {
|
||||||
let window = docShell.DOMWindow;
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
let window = webProgress.DOMWindow;
|
||||||
let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIDOMWindowUtils)
|
.getInterface(Ci.nsIDOMWindowUtils)
|
||||||
.outerWindowID;
|
.outerWindowID;
|
||||||
|
@ -997,6 +1035,7 @@ TabActor.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifyDocShellDestroy: function (webProgress) {
|
_notifyDocShellDestroy: function (webProgress) {
|
||||||
|
webProgress = webProgress.QueryInterface(Ci.nsIWebProgress);
|
||||||
let id = webProgress.DOMWindow
|
let id = webProgress.DOMWindow
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIDOMWindowUtils)
|
.getInterface(Ci.nsIDOMWindowUtils)
|
||||||
|
@ -1096,15 +1135,17 @@ TabActor.prototype = {
|
||||||
if (this.docShell) {
|
if (this.docShell) {
|
||||||
this._progressListener.unwatch(this.docShell);
|
this._progressListener.unwatch(this.docShell);
|
||||||
}
|
}
|
||||||
this._progressListener.destroy();
|
if (this._progressListener) {
|
||||||
this._progressListener = null;
|
this._progressListener.destroy();
|
||||||
this._originalWindow = null;
|
this._progressListener = null;
|
||||||
|
this._originalWindow = null;
|
||||||
|
|
||||||
// Removes the observers being set in _watchDocShells
|
// Removes the observers being set in _watchDocShells
|
||||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
if (this.listenForNewDocShells) {
|
||||||
Services.obs.removeObserver(this, "webnavigation-create", false);
|
Services.obs.removeObserver(this, "webnavigation-create");
|
||||||
|
}
|
||||||
|
Services.obs.removeObserver(this, "webnavigation-destroy");
|
||||||
}
|
}
|
||||||
Services.obs.removeObserver(this, "webnavigation-destroy", false);
|
|
||||||
|
|
||||||
this._popContext();
|
this._popContext();
|
||||||
|
|
||||||
|
@ -1304,9 +1345,11 @@ TabActor.prototype = {
|
||||||
|
|
||||||
this._windowDestroyed(this.window, null, true);
|
this._windowDestroyed(this.window, null, true);
|
||||||
|
|
||||||
DevToolsUtils.executeSoon(() => {
|
// Immediately change the window as this window, if in process of unload
|
||||||
this._setWindow(window);
|
// may already be non working on the next cycle and start throwing
|
||||||
|
this._setWindow(window);
|
||||||
|
|
||||||
|
DevToolsUtils.executeSoon(() => {
|
||||||
// Then fake window-ready and navigate on the given document
|
// Then fake window-ready and navigate on the given document
|
||||||
this._windowReady(window, true);
|
this._windowReady(window, true);
|
||||||
DevToolsUtils.executeSoon(() => {
|
DevToolsUtils.executeSoon(() => {
|
||||||
|
@ -2018,11 +2061,7 @@ DebuggerProgressListener.prototype = {
|
||||||
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
|
||||||
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||||
|
|
||||||
// TODO: fix docShell.chromeEventHandler in child processes!
|
let handler = getDocShellChromeEventHandler(docShell);
|
||||||
let handler = docShell.chromeEventHandler ||
|
|
||||||
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
|
||||||
|
|
||||||
handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||||
handler.addEventListener("pageshow", this._onWindowCreated, true);
|
handler.addEventListener("pageshow", this._onWindowCreated, true);
|
||||||
handler.addEventListener("pagehide", this._onWindowHidden, true);
|
handler.addEventListener("pagehide", this._onWindowHidden, true);
|
||||||
|
@ -2042,11 +2081,7 @@ DebuggerProgressListener.prototype = {
|
||||||
webProgress.removeProgressListener(this);
|
webProgress.removeProgressListener(this);
|
||||||
} catch(e) {}
|
} catch(e) {}
|
||||||
|
|
||||||
// TODO: fix docShell.chromeEventHandler in child processes!
|
let handler = getDocShellChromeEventHandler(docShell);
|
||||||
let handler = docShell.chromeEventHandler ||
|
|
||||||
docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
|
||||||
|
|
||||||
handler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
handler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
|
||||||
handler.removeEventListener("pageshow", this._onWindowCreated, true);
|
handler.removeEventListener("pageshow", this._onWindowCreated, true);
|
||||||
handler.removeEventListener("pagehide", this._onWindowHidden, true);
|
handler.removeEventListener("pagehide", this._onWindowHidden, true);
|
||||||
|
@ -2057,18 +2092,10 @@ DebuggerProgressListener.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_getWindowsInDocShell: function(docShell) {
|
_getWindowsInDocShell: function(docShell) {
|
||||||
let docShellsEnum = docShell.getDocShellEnumerator(
|
return getChildDocShells(docShell).map(d => {
|
||||||
Ci.nsIDocShellTreeItem.typeAll,
|
return d.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
Ci.nsIDocShell.ENUMERATE_FORWARDS
|
.getInterface(Ci.nsIDOMWindow);
|
||||||
);
|
});
|
||||||
|
|
||||||
let windows = [];
|
|
||||||
while (docShellsEnum.hasMoreElements()) {
|
|
||||||
let w = docShellsEnum.getNext().QueryInterface(Ci.nsIInterfaceRequestor)
|
|
||||||
.getInterface(Ci.nsIDOMWindow);
|
|
||||||
windows.push(w);
|
|
||||||
}
|
|
||||||
return windows;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {
|
onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {
|
||||||
|
|
|
@ -1503,6 +1503,9 @@ WebConsoleActor.prototype =
|
||||||
// This method is called after this.window is changed,
|
// This method is called after this.window is changed,
|
||||||
// so we register new listener on this new window
|
// so we register new listener on this new window
|
||||||
this.onStartListeners({listeners: listeners});
|
this.onStartListeners({listeners: listeners});
|
||||||
|
|
||||||
|
// Also reset the cached top level chrome window being targeted
|
||||||
|
this._lastChromeWindow = null;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,11 @@ var DebuggerServer = {
|
||||||
*/
|
*/
|
||||||
chromeWindowType: null,
|
chromeWindowType: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow debugging chrome of (parent or child) processes.
|
||||||
|
*/
|
||||||
|
allowChromeProcess: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the debugger server.
|
* Initialize the debugger server.
|
||||||
*/
|
*/
|
||||||
|
@ -366,8 +371,6 @@ var DebuggerServer = {
|
||||||
|
|
||||||
if (!restrictPrivileges) {
|
if (!restrictPrivileges) {
|
||||||
this.addTabActors();
|
this.addTabActors();
|
||||||
let { ChromeDebuggerActor } = require("devtools/server/actors/script");
|
|
||||||
this.addGlobalActor(ChromeDebuggerActor, "chromeDebugger");
|
|
||||||
this.registerModule("devtools/server/actors/preference", {
|
this.registerModule("devtools/server/actors/preference", {
|
||||||
prefix: "preference",
|
prefix: "preference",
|
||||||
constructor: "PreferenceActor",
|
constructor: "PreferenceActor",
|
||||||
|
@ -430,12 +433,12 @@ var DebuggerServer = {
|
||||||
this.registerModule("devtools/server/actors/webconsole", {
|
this.registerModule("devtools/server/actors/webconsole", {
|
||||||
prefix: "console",
|
prefix: "console",
|
||||||
constructor: "WebConsoleActor",
|
constructor: "WebConsoleActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/inspector", {
|
this.registerModule("devtools/server/actors/inspector", {
|
||||||
prefix: "inspector",
|
prefix: "inspector",
|
||||||
constructor: "InspectorActor",
|
constructor: "InspectorActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/call-watcher", {
|
this.registerModule("devtools/server/actors/call-watcher", {
|
||||||
prefix: "callWatcher",
|
prefix: "callWatcher",
|
||||||
|
@ -445,27 +448,27 @@ var DebuggerServer = {
|
||||||
this.registerModule("devtools/server/actors/canvas", {
|
this.registerModule("devtools/server/actors/canvas", {
|
||||||
prefix: "canvas",
|
prefix: "canvas",
|
||||||
constructor: "CanvasActor",
|
constructor: "CanvasActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/webgl", {
|
this.registerModule("devtools/server/actors/webgl", {
|
||||||
prefix: "webgl",
|
prefix: "webgl",
|
||||||
constructor: "WebGLActor",
|
constructor: "WebGLActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/webaudio", {
|
this.registerModule("devtools/server/actors/webaudio", {
|
||||||
prefix: "webaudio",
|
prefix: "webaudio",
|
||||||
constructor: "WebAudioActor",
|
constructor: "WebAudioActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/stylesheets", {
|
this.registerModule("devtools/server/actors/stylesheets", {
|
||||||
prefix: "styleSheets",
|
prefix: "styleSheets",
|
||||||
constructor: "StyleSheetsActor",
|
constructor: "StyleSheetsActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/styleeditor", {
|
this.registerModule("devtools/server/actors/styleeditor", {
|
||||||
prefix: "styleEditor",
|
prefix: "styleEditor",
|
||||||
constructor: "StyleEditorActor",
|
constructor: "StyleEditorActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/storage", {
|
this.registerModule("devtools/server/actors/storage", {
|
||||||
prefix: "storage",
|
prefix: "storage",
|
||||||
|
@ -485,17 +488,17 @@ var DebuggerServer = {
|
||||||
this.registerModule("devtools/server/actors/memory", {
|
this.registerModule("devtools/server/actors/memory", {
|
||||||
prefix: "memory",
|
prefix: "memory",
|
||||||
constructor: "MemoryActor",
|
constructor: "MemoryActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/framerate", {
|
this.registerModule("devtools/server/actors/framerate", {
|
||||||
prefix: "framerate",
|
prefix: "framerate",
|
||||||
constructor: "FramerateActor",
|
constructor: "FramerateActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/eventlooplag", {
|
this.registerModule("devtools/server/actors/eventlooplag", {
|
||||||
prefix: "eventLoopLag",
|
prefix: "eventLoopLag",
|
||||||
constructor: "EventLoopLagActor",
|
constructor: "EventLoopLagActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/layout", {
|
this.registerModule("devtools/server/actors/layout", {
|
||||||
prefix: "reflow",
|
prefix: "reflow",
|
||||||
|
@ -505,17 +508,17 @@ var DebuggerServer = {
|
||||||
this.registerModule("devtools/server/actors/csscoverage", {
|
this.registerModule("devtools/server/actors/csscoverage", {
|
||||||
prefix: "cssUsage",
|
prefix: "cssUsage",
|
||||||
constructor: "CSSUsageActor",
|
constructor: "CSSUsageActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/monitor", {
|
this.registerModule("devtools/server/actors/monitor", {
|
||||||
prefix: "monitor",
|
prefix: "monitor",
|
||||||
constructor: "MonitorActor",
|
constructor: "MonitorActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/timeline", {
|
this.registerModule("devtools/server/actors/timeline", {
|
||||||
prefix: "timeline",
|
prefix: "timeline",
|
||||||
constructor: "TimelineActor",
|
constructor: "TimelineActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
this.registerModule("devtools/server/actors/director-manager", {
|
this.registerModule("devtools/server/actors/director-manager", {
|
||||||
prefix: "directorManager",
|
prefix: "directorManager",
|
||||||
|
@ -526,13 +529,13 @@ var DebuggerServer = {
|
||||||
this.registerModule("devtools/server/actors/profiler", {
|
this.registerModule("devtools/server/actors/profiler", {
|
||||||
prefix: "profiler",
|
prefix: "profiler",
|
||||||
constructor: "ProfilerActor",
|
constructor: "ProfilerActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.registerModule("devtools/server/actors/animation", {
|
this.registerModule("devtools/server/actors/animation", {
|
||||||
prefix: "animations",
|
prefix: "animations",
|
||||||
constructor: "AnimationsActor",
|
constructor: "AnimationsActor",
|
||||||
type: { global: true, tab: true }
|
type: { tab: true }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ EXTRA_JS_MODULES.devtools.server.actors += [
|
||||||
'actors/canvas.js',
|
'actors/canvas.js',
|
||||||
'actors/child-process.js',
|
'actors/child-process.js',
|
||||||
'actors/childtab.js',
|
'actors/childtab.js',
|
||||||
|
'actors/chrome.js',
|
||||||
'actors/common.js',
|
'actors/common.js',
|
||||||
'actors/csscoverage.js',
|
'actors/csscoverage.js',
|
||||||
'actors/device.js',
|
'actors/device.js',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче