зеркало из https://github.com/mozilla/gecko-dev.git
199 строки
6.4 KiB
JavaScript
199 строки
6.4 KiB
JavaScript
/* 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("./tab");
|
|
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.getProcess 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 connection DebuggerServerConnection
|
|
* The connection to the client.
|
|
*/
|
|
function ChromeActor(connection) {
|
|
TabActor.call(this, connection);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// We really want _some_ window at least, so fallback to the hidden window if
|
|
// there's nothing else (such as during early startup).
|
|
if (!window) {
|
|
try {
|
|
window = Services.appShell.hiddenDOMWindow;
|
|
} catch (e) {
|
|
// On XPCShell, the above line will throw.
|
|
}
|
|
}
|
|
|
|
// 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(subject, topic, data) {
|
|
TabActor.prototype.observe.call(this, subject, topic, data);
|
|
if (!this.attached) {
|
|
return;
|
|
}
|
|
|
|
subject.QueryInterface(Ci.nsIDocShell);
|
|
|
|
if (topic == "chrome-webnavigation-create") {
|
|
this._onDocShellCreated(subject);
|
|
} else if (topic == "chrome-webnavigation-destroy") {
|
|
this._onDocShellDestroy(subject);
|
|
}
|
|
};
|
|
|
|
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");
|
|
Services.obs.addObserver(this, "chrome-webnavigation-destroy");
|
|
|
|
// Iterate over all top-level windows.
|
|
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);
|
|
}
|
|
return undefined;
|
|
};
|
|
|
|
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 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);
|
|
return undefined;
|
|
};
|
|
|
|
/* 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(nestData) {
|
|
// 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);
|
|
}
|
|
};
|