summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/chrome.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/chrome.js')
-rw-r--r--devtools/server/actors/chrome.js185
1 files changed, 185 insertions, 0 deletions
diff --git a/devtools/server/actors/chrome.js b/devtools/server/actors/chrome.js
new file mode 100644
index 000000000..07cd2ad99
--- /dev/null
+++ b/devtools/server/actors/chrome.js
@@ -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.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 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);
+ }
+};