diff --git a/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_fission_inspector.js b/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_fission_inspector.js index d641de027473..de29d62e4534 100644 --- a/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_fission_inspector.js +++ b/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_fission_inspector.js @@ -18,16 +18,6 @@ add_task(async function() { // Forces the Browser Toolbox to open on the inspector by default await pushPref("devtools.browsertoolbox.panel", "inspector"); - // Open the tab *before* opening the Browser Toolbox in order to already have the document - // loaded before it starts iterating over additional frame targets. - // Bug 1593937 should make it optional and be able to care about dynamically added targets. - const tab = await addTab( - `data:text/html,
Foo
Foo
` - ); - - // Set a custom attribute on the tab's browser, in order to easily select it in the markup view - tab.linkedBrowser.setAttribute("test-tab", "true"); - const ToolboxTask = await initBrowserToolboxTask({ enableBrowserToolboxFission: true, }); @@ -35,6 +25,14 @@ add_task(async function() { selectNodeFront, }); + // Open the tab *after* opening the Browser Toolbox in order to force creating the remote frames + // late and exercise frame target watching code. + const tab = await addTab( + `data:text/html,
Foo
Foo
` + ); + // Set a custom attribute on the tab's browser, in order to easily select it in the markup view + tab.linkedBrowser.setAttribute("test-tab", "true"); + const color = await ToolboxTask.spawn(null, async () => { /* global gToolbox */ const inspector = gToolbox.getPanel("inspector"); diff --git a/devtools/client/fronts/descriptors/frame.js b/devtools/client/fronts/descriptors/frame.js index bde01a9668bb..eca425118c4b 100644 --- a/devtools/client/fronts/descriptors/frame.js +++ b/devtools/client/fronts/descriptors/frame.js @@ -93,6 +93,15 @@ class FrameDescriptorFront extends FrontClassWithSpec(frameDescriptorSpec) { return parentDescriptor.getTarget(); } + getCachedWatcher() { + for (const child of this.poolChildren()) { + if (child.typeName == "watcher") { + return child; + } + } + return null; + } + destroy() { this._frameTargetFront = null; this._targetFrontPromise = null; diff --git a/devtools/client/fronts/descriptors/process.js b/devtools/client/fronts/descriptors/process.js index 19f888dd468f..58bcda1edfc0 100644 --- a/devtools/client/fronts/descriptors/process.js +++ b/devtools/client/fronts/descriptors/process.js @@ -29,6 +29,7 @@ class ProcessDescriptorFront extends FrontClassWithSpec(processDescriptorSpec) { form(json) { this.id = json.id; this.isParent = json.isParent; + this.traits = json.traits || {}; } async _createProcessTargetFront(form) { @@ -92,6 +93,15 @@ class ProcessDescriptorFront extends FrontClassWithSpec(processDescriptorSpec) { return this._targetFrontPromise; } + getCachedWatcher() { + for (const child of this.poolChildren()) { + if (child.typeName == "watcher") { + return child; + } + } + return null; + } + destroy() { if (this._processTargetFront) { this._processTargetFront.destroy(); diff --git a/devtools/client/fronts/descriptors/tab.js b/devtools/client/fronts/descriptors/tab.js index f2f02f053242..42991ce82c14 100644 --- a/devtools/client/fronts/descriptors/tab.js +++ b/devtools/client/fronts/descriptors/tab.js @@ -143,6 +143,15 @@ class TabDescriptorFront extends FrontClassWithSpec(tabDescriptorSpec) { })(); return this._targetFrontPromise; } + + getCachedWatcher() { + for (const child of this.poolChildren()) { + if (child.typeName == "watcher") { + return child; + } + } + return null; + } } exports.TabDescriptorFront = TabDescriptorFront; diff --git a/devtools/client/fronts/moz.build b/devtools/client/fronts/moz.build index 0fcdd630550a..879c125d706a 100644 --- a/devtools/client/fronts/moz.build +++ b/devtools/client/fronts/moz.build @@ -47,6 +47,7 @@ DevToolsModules( 'symbol-iterator.js', 'thread.js', 'walker.js', + 'watcher.js', 'webconsole.js', 'websocket.js' ) diff --git a/devtools/client/fronts/watcher.js b/devtools/client/fronts/watcher.js new file mode 100644 index 000000000000..6d08213f9282 --- /dev/null +++ b/devtools/client/fronts/watcher.js @@ -0,0 +1,49 @@ +/* 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 { watcherSpec } = require("devtools/shared/specs/watcher"); +const { + FrontClassWithSpec, + registerFront, +} = require("devtools/shared/protocol"); + +loader.lazyRequireGetter( + this, + "BrowsingContextTargetFront", + "devtools/client/fronts/targets/browsing-context", + true +); + +class WatcherFront extends FrontClassWithSpec(watcherSpec) { + constructor(client, targetFront, parentFront) { + super(client, targetFront, parentFront); + + this._onTargetAvailable = this._onTargetAvailable.bind(this); + this._onTargetDestroyed = this._onTargetDestroyed.bind(this); + + // Convert form, which is just JSON object to Fronts for these two events + this.on("target-available-form", this._onTargetAvailable); + this.on("target-destroyed-form", this._onTargetDestroyed); + } + + form(json) { + this.actorID = json.actor; + this.traits = json.traits; + } + + _onTargetAvailable(form) { + const front = new BrowsingContextTargetFront(this.conn, null, this); + front.actorID = form.actor; + front.form(form); + this.manage(front); + this.emit("target-available", front); + } + + _onTargetDestroyed(form) { + const front = this.actor(form.actor); + this.emit("target-destroyed", front); + } +} +registerFront(WatcherFront); diff --git a/devtools/server/actors/descriptors/frame.js b/devtools/server/actors/descriptors/frame.js index 9bcdbfa2a640..873ca70f0b78 100644 --- a/devtools/server/actors/descriptors/frame.js +++ b/devtools/server/actors/descriptors/frame.js @@ -25,7 +25,7 @@ loader.lazyRequireGetter( const FrameDescriptorActor = ActorClassWithSpec(frameDescriptorSpec, { initialize(connection, browsingContext) { if (typeof browsingContext.id != "number") { - throw Error("Frame Descriptor Connect requires a valid browsingContext."); + throw Error("Frame Descriptor requires a valid BrowsingContext."); } Actor.prototype.initialize.call(this, connection); this.destroy = this.destroy.bind(this); diff --git a/devtools/server/actors/descriptors/moz.build b/devtools/server/actors/descriptors/moz.build index 83ac853a6135..4dc26c0ac636 100644 --- a/devtools/server/actors/descriptors/moz.build +++ b/devtools/server/actors/descriptors/moz.build @@ -4,6 +4,10 @@ # 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/. +DIRS += [ + 'watcher', +] + DevToolsModules( 'frame.js', 'process.js', diff --git a/devtools/server/actors/descriptors/process.js b/devtools/server/actors/descriptors/process.js index b031d61ad916..0565d0498328 100644 --- a/devtools/server/actors/descriptors/process.js +++ b/devtools/server/actors/descriptors/process.js @@ -31,6 +31,12 @@ loader.lazyRequireGetter( "devtools/server/connectors/content-process-connector", true ); +loader.lazyRequireGetter( + this, + "WatcherActor", + "devtools/server/actors/descriptors/watcher/watcher", + true +); const ProcessDescriptorActor = ActorClassWithSpec(processDescriptorSpec, { initialize(connection, options = {}) { @@ -129,11 +135,28 @@ const ProcessDescriptorActor = ActorClassWithSpec(processDescriptorSpec, { return this._childProcessConnect(); }, + /** + * Return a Watcher actor, allowing to keep track of targets which + * already exists or will be created. It also helps knowing when they + * are destroyed. + */ + getWatcher() { + if (!this.watcher) { + this.watcher = new WatcherActor(this.conn); + this.manage(this.watcher); + } + return this.watcher; + }, + form() { return { actor: this.actorID, id: this.id, isParent: this.isParent, + traits: { + // FF77+ supports the Watcher actor + watcher: true, + }, }; }, diff --git a/devtools/server/actors/descriptors/tab.js b/devtools/server/actors/descriptors/tab.js index a6d40d3f424d..53319f9510a1 100644 --- a/devtools/server/actors/descriptors/tab.js +++ b/devtools/server/actors/descriptors/tab.js @@ -25,6 +25,13 @@ const { ActorClassWithSpec, Actor } = require("devtools/shared/protocol"); const { tabDescriptorSpec } = require("devtools/shared/specs/descriptors/tab"); const { AppConstants } = require("resource://gre/modules/AppConstants.jsm"); +loader.lazyRequireGetter( + this, + "WatcherActor", + "devtools/server/actors/descriptors/watcher/watcher", + true +); + /** * Creates a target actor proxy for handling requests to a single browser frame. * Both and