diff --git a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js index 746820adfb26..7f5c5c818340 100644 --- a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js +++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js @@ -91,17 +91,7 @@ add_task(async function testWebExtensionsToolboxSwitchToPopup() { /* eslint-disable no-undef */ let jsterm; - const popupFramePromise = new Promise(resolve => { - const listener = data => { - if (data.frames.some(({url}) => url && url.endsWith("popup.html"))) { - toolbox.target.off("frame-update", listener); - resolve(); - } - }; - toolbox.target.on("frame-update", listener); - }); - - const waitForFrameListUpdate = toolbox.target.once("frame-update"); + let popupFramePromise; toolbox.selectTool("webconsole") .then(async (console) => { @@ -121,6 +111,18 @@ add_task(async function testWebExtensionsToolboxSwitchToPopup() { await clickNoAutoHideMenu(); dump(`Clicked the menu button\n`); + popupFramePromise = new Promise(resolve => { + const listener = data => { + if (data.frames.some(({url}) => url && url.endsWith("popup.html"))) { + toolbox.target.off("frame-update", listener); + resolve(); + } + }; + toolbox.target.on("frame-update", listener); + }); + + const waitForFrameListUpdate = toolbox.target.once("frame-update"); + jsterm = console.hud.jsterm; jsterm.execute("myWebExtensionShowPopup()"); diff --git a/devtools/client/accessibility/test/browser/head.js b/devtools/client/accessibility/test/browser/head.js index 531917a33e31..17b450a57e76 100644 --- a/devtools/client/accessibility/test/browser/head.js +++ b/devtools/client/accessibility/test/browser/head.js @@ -408,6 +408,6 @@ function reload(target, waitForTargetEvent = "navigate") { * @param {String} waitForTargetEvent Event to wait for after reload. */ function navigate(target, url, waitForTargetEvent = "navigate") { - executeSoon(() => target.activeTab.navigateTo({ url })); + executeSoon(() => target.activeTab.navigateTo(url)); return once(target, waitForTargetEvent); } diff --git a/devtools/client/application/initializer.js b/devtools/client/application/initializer.js index 4e4f4432c791..683d4859126f 100644 --- a/devtools/client/application/initializer.js +++ b/devtools/client/application/initializer.js @@ -43,7 +43,8 @@ window.Application = { return toolbox.selectTool(toolId); } }; - this.toolbox.target.activeTab.on("workerListChanged", this.updateWorkers); + + this.client.addListener("workerListChanged", this.updateWorkers); this.client.addListener("serviceWorkerRegistrationListChanged", this.updateWorkers); this.client.addListener("registration-changed", this.updateWorkers); this.client.addListener("processListChanged", this.updateWorkers); @@ -88,7 +89,7 @@ window.Application = { }, destroy() { - this.toolbox.target.activeTab.off("workerListChanged", this.updateWorkers); + this.client.removeListener("workerListChanged", this.updateWorkers); this.client.removeListener("serviceWorkerRegistrationListChanged", this.updateWorkers); this.client.removeListener("registration-changed", this.updateWorkers); diff --git a/devtools/client/application/test/head.js b/devtools/client/application/test/head.js index c81d6a2cc2e2..6f6dc9d97884 100644 --- a/devtools/client/application/test/head.js +++ b/devtools/client/application/test/head.js @@ -41,7 +41,7 @@ function getWorkerContainers(doc) { } function navigate(target, url, waitForTargetEvent = "navigate") { - executeSoon(() => target.activeTab.navigateTo({ url })); + executeSoon(() => target.activeTab.navigateTo(url)); return once(target, waitForTargetEvent); } diff --git a/devtools/client/canvasdebugger/test/head.js b/devtools/client/canvasdebugger/test/head.js index fcbd14ece28d..299ae1ebeb6a 100644 --- a/devtools/client/canvasdebugger/test/head.js +++ b/devtools/client/canvasdebugger/test/head.js @@ -107,7 +107,7 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate" } function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { - executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl })); + executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); return once(aTarget, aWaitForTargetEvent); } diff --git a/devtools/client/debugger/debugger-controller.js b/devtools/client/debugger/debugger-controller.js index af4394ece86e..3a194b9b47ac 100644 --- a/devtools/client/debugger/debugger-controller.js +++ b/devtools/client/debugger/debugger-controller.js @@ -478,22 +478,11 @@ Workers.prototype = { } this._updateWorkerList(); - - // `_tabClient` can be BrowsingContextTargetFront (protocol.js front) or - // WorkerClient/DebuggerClient (old fashion client) - if (typeof(this._tabClient.on) == "function") { - this._tabClient.on("workerListChanged", this._onWorkerListChanged); - } else { - this._tabClient.addListener("workerListChanged", this._onWorkerListChanged); - } + this._tabClient.addListener("workerListChanged", this._onWorkerListChanged); }, disconnect: function () { - if (typeof(this._tabClient.on) == "function") { - this._tabClient.off("workerListChanged", this._onWorkerListChanged); - } else { - this._tabClient.removeListener("workerListChanged", this._onWorkerListChanged); - } + this._tabClient.removeListener("workerListChanged", this._onWorkerListChanged); }, _updateWorkerList: function () { diff --git a/devtools/client/debugger/new/src/client/firefox/commands.js b/devtools/client/debugger/new/src/client/firefox/commands.js index 5698dc744475..16415c5620bc 100644 --- a/devtools/client/debugger/new/src/client/firefox/commands.js +++ b/devtools/client/debugger/new/src/client/firefox/commands.js @@ -247,7 +247,7 @@ function debuggeeCommand(script) { } function navigate(url) { - return tabTarget.activeTab.navigateTo({ url }); + return tabTarget.activeTab.navigateTo(url); } function reload() { @@ -455,4 +455,4 @@ const clientCommands = { setSkipPausing }; exports.setupCommands = setupCommands; -exports.clientCommands = clientCommands; +exports.clientCommands = clientCommands; \ No newline at end of file diff --git a/devtools/client/debugger/new/src/client/firefox/events.js b/devtools/client/debugger/new/src/client/firefox/events.js index 6499900453f6..ee297a88dbdb 100644 --- a/devtools/client/debugger/new/src/client/firefox/events.js +++ b/devtools/client/debugger/new/src/client/firefox/events.js @@ -41,13 +41,7 @@ function setupEvents(dependencies) { }); if (threadClient._parent) { - // Parent may be BrowsingContextTargetFront and be protocol.js. - // Or DebuggerClient/WorkerClient and still be old fashion actor. - if (threadClient._parent.on) { - threadClient._parent.on("workerListChanged", workerListChanged); - } else { - threadClient._parent.addListener("workerListChanged", workerListChanged); - } + threadClient._parent.addListener("workerListChanged", workerListChanged); } } } @@ -119,4 +113,4 @@ const clientEvents = { newSource }; exports.setupEvents = setupEvents; -exports.clientEvents = clientEvents; +exports.clientEvents = clientEvents; \ No newline at end of file diff --git a/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js b/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js index c7291752fa71..5c7c0a50b8e5 100644 --- a/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js +++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-inline-cache.js @@ -76,7 +76,7 @@ add_task(async function() { ); info("Disable HTTP cache for page"); - await toolbox.target.activeTab.reconfigure({ options: { cacheDisabled: true } }); + await toolbox.target.activeTab.reconfigure({ cacheDisabled: true }); makeChanges(); info("Reload inside debugger with toolbox caching disabled (attempt 1)"); @@ -106,7 +106,7 @@ add_task(async function() { ); info("Enable HTTP cache for page"); - await toolbox.target.activeTab.reconfigure({ options: { cacheDisabled: false } }); + await toolbox.target.activeTab.reconfigure({ cacheDisabled: false }); makeChanges(); // Even though the HTTP cache is now enabled, Gecko sets the VALIDATE_ALWAYS flag when diff --git a/devtools/client/debugger/test/mochitest/head.js b/devtools/client/debugger/test/mochitest/head.js index 63db76e75fc6..83ef63c11596 100644 --- a/devtools/client/debugger/test/mochitest/head.js +++ b/devtools/client/debugger/test/mochitest/head.js @@ -180,8 +180,8 @@ function getAddonActorForId(aClient, aAddonId) { async function attachTargetActorForUrl(aClient, aUrl) { let grip = await getTargetActorForUrl(aClient, aUrl); - let [ response, front ] = await aClient.attachTarget(grip.actor); - return [grip, response, front]; + let [ response ] = await aClient.attachTarget(grip.actor); + return [grip, response]; } async function attachThreadActorForUrl(aClient, aUrl) { @@ -450,7 +450,7 @@ function ensureThreadClientState(aPanel, aState) { function reload(aPanel, aUrl) { let activeTab = aPanel.panelWin.DebuggerController._target.activeTab; - aUrl ? activeTab.navigateTo({ url: aUrl }) : activeTab.reload(); + aUrl ? activeTab.navigateTo(aUrl) : activeTab.reload(); } function navigateActiveTabTo(aPanel, aUrl, aWaitForEventName, aEventRepeat) { @@ -1109,9 +1109,14 @@ function attachWorker(tabClient, worker) { return tabClient.attachWorker(worker.actor); } -function waitForWorkerListChanged(targetFront) { +function waitForWorkerListChanged(tabClient) { info("Waiting for worker list to change."); - return targetFront.once("workerListChanged"); + return new Promise(function (resolve) { + tabClient.addListener("workerListChanged", function listener() { + tabClient.removeListener("workerListChanged", listener); + resolve(); + }); + }); } function attachThread(workerClient, options) { diff --git a/devtools/client/framework/target.js b/devtools/client/framework/target.js index 193cae5fd0cf..c11e813b315e 100644 --- a/devtools/client/framework/target.js +++ b/devtools/client/framework/target.js @@ -194,7 +194,6 @@ const TargetFactory = exports.TargetFactory = { function TabTarget({ form, client, chrome, tab = null }) { EventEmitter.decorate(this); this.destroy = this.destroy.bind(this); - this._onTabNavigated = this._onTabNavigated.bind(this); this.activeTab = this.activeConsole = null; this._form = form; @@ -519,12 +518,6 @@ TabTarget.prototype = { const [response, tabClient] = await this._client.attachTarget(this._form.actor); this.activeTab = tabClient; this.threadActor = response.threadActor; - - this.activeTab.on("tabNavigated", this._onTabNavigated); - this._onFrameUpdate = packet => { - this.emit("frame-update", packet); - }; - this.activeTab.on("frameUpdate", this._onFrameUpdate); }; // Attach the console actor @@ -556,6 +549,8 @@ TabTarget.prototype = { this._title = form.title; } + this._setupRemoteListeners(); + // AddonActor and chrome debugging on RootActor don't inherit from // BrowsingContextTargetActor (i.e. this.isBrowsingContext=false) and don't need // to be attached. @@ -563,10 +558,6 @@ TabTarget.prototype = { await attachTarget(); } - // _setupRemoteListeners has to be called after the potential call to `attachTarget` - // as it depends on `activeTab` which is set by this method. - this._setupRemoteListeners(); - // But all target actor have a console actor to attach return attachConsole(); })(); @@ -594,95 +585,70 @@ TabTarget.prototype = { this._tab.removeEventListener("TabRemotenessChange", this); }, - /** - * Event listener for tabNavigated packet sent by activeTab's front. - */ - _onTabNavigated: function(packet) { - const event = Object.create(null); - event.url = packet.url; - event.title = packet.title; - event.nativeConsoleAPI = packet.nativeConsoleAPI; - event.isFrameSwitching = packet.isFrameSwitching; - - // Keep the title unmodified when a developer toolbox switches frame - // for a tab (Bug 1261687), but always update the title when the target - // is a WebExtension (where the addon name is always included in the title - // and the url is supposed to be updated every time the selected frame changes). - if (!packet.isFrameSwitching || this.isWebExtension) { - this._url = packet.url; - this._title = packet.title; - } - - // Send any stored event payload (DOMWindow or nsIRequest) for backwards - // compatibility with non-remotable tools. - if (packet.state == "start") { - event._navPayload = this._navRequest; - this.emit("will-navigate", event); - this._navRequest = null; - } else { - event._navPayload = this._navWindow; - this.emit("navigate", event); - this._navWindow = null; - } - }, - /** * Setup listeners for remote debugging, updating existing ones as necessary. */ _setupRemoteListeners: function() { this.client.addListener("closed", this.destroy); - // For now, only browsing-context inherited actors are using a front, - // for which events have to be listened on the front itself. - // For other actors (ContentProcessTargetActor and AddonTargetActor), events should - // still be listened directly on the client. This should be ultimately cleaned up to - // only listen from a front by bug 1465635. - if (this.activeTab) { - this.activeTab.on("tabDetached", this.destroy); + this._onTabDetached = (type, packet) => { + // We have to filter message to ensure that this detach is for this tab + if (packet.from == this._form.actor) { + this.destroy(); + } + }; + this.client.addListener("tabDetached", this._onTabDetached); - // These events should be ultimately listened from the thread client as - // they are coming from it and no longer go through the Target Actor/Front. - this._onSourceUpdated = packet => this.emit("source-updated", packet); - this.activeTab.on("newSource", this._onSourceUpdated); - this.activeTab.on("updatedSource", this._onSourceUpdated); - } else { - this._onTabDetached = (type, packet) => { - // We have to filter message to ensure that this detach is for this tab - if (packet.from == this._form.actor) { - this.destroy(); - } - }; - this.client.addListener("tabDetached", this._onTabDetached); + this._onTabNavigated = (type, packet) => { + const event = Object.create(null); + event.url = packet.url; + event.title = packet.title; + event.nativeConsoleAPI = packet.nativeConsoleAPI; + event.isFrameSwitching = packet.isFrameSwitching; - this._onSourceUpdated = (type, packet) => this.emit("source-updated", packet); - this.client.addListener("newSource", this._onSourceUpdated); - this.client.addListener("updatedSource", this._onSourceUpdated); - } + // Keep the title unmodified when a developer toolbox switches frame + // for a tab (Bug 1261687), but always update the title when the target + // is a WebExtension (where the addon name is always included in the title + // and the url is supposed to be updated every time the selected frame changes). + if (!packet.isFrameSwitching || this.isWebExtension) { + this._url = packet.url; + this._title = packet.title; + } + + // Send any stored event payload (DOMWindow or nsIRequest) for backwards + // compatibility with non-remotable tools. + if (packet.state == "start") { + event._navPayload = this._navRequest; + this.emit("will-navigate", event); + this._navRequest = null; + } else { + event._navPayload = this._navWindow; + this.emit("navigate", event); + this._navWindow = null; + } + }; + this.client.addListener("tabNavigated", this._onTabNavigated); + + this._onFrameUpdate = (type, packet) => { + this.emit("frame-update", packet); + }; + this.client.addListener("frameUpdate", this._onFrameUpdate); + + this._onSourceUpdated = (event, packet) => this.emit("source-updated", packet); + this.client.addListener("newSource", this._onSourceUpdated); + this.client.addListener("updatedSource", this._onSourceUpdated); }, /** * Teardown listeners for remote debugging. */ _teardownRemoteListeners: function() { - // Remove listeners set in _setupRemoteListeners this.client.removeListener("closed", this.destroy); - if (this.activeTab) { - this.activeTab.off("tabDetached", this.destroy); - this.activeTab.off("newSource", this._onSourceUpdated); - this.activeTab.off("updatedSource", this._onSourceUpdated); - } else { - this.client.removeListener("tabDetached", this._onTabDetached); - this.client.removeListener("newSource", this._onSourceUpdated); - this.client.removeListener("updatedSource", this._onSourceUpdated); - } - - // Remove listeners set in attachTarget - if (this.activeTab) { - this.activeTab.off("tabNavigated", this._onTabNavigated); - this.activeTab.off("frameUpdate", this._onFrameUpdate); - } - - // Remove listeners set in attachConsole + this.client.removeListener("tabNavigated", this._onTabNavigated); + this.client.removeListener("tabDetached", this._onTabDetached); + this.client.removeListener("frameUpdate", this._onFrameUpdate); + this.client.removeListener("newSource", this._onSourceUpdated); + this.client.removeListener("updatedSource", this._onSourceUpdated); if (this.activeConsole && this._onInspectObject) { this.activeConsole.off("inspectObject", this._onInspectObject); } @@ -775,11 +741,7 @@ TabTarget.prototype = { // it. We just need to detach from the tab, if already attached. // |detach| may fail if the connection is already dead, so proceed with // cleanup directly after this. - try { - await this.activeTab.detach(); - } catch (e) { - console.warn(`Error while detaching target: ${e.message}`); - } + this.activeTab.detach(); cleanupAndResolve(); } else { cleanupAndResolve(); @@ -828,7 +790,7 @@ TabTarget.prototype = { logErrorInPage: function(text, category) { if (this.activeTab && this.activeTab.traits.logInPage) { const errorFlag = 0; - this.activeTab.logInPage({ text, category, flags: errorFlag }); + this.activeTab.logInPage(text, category, errorFlag); } }, @@ -843,7 +805,7 @@ TabTarget.prototype = { logWarningInPage: function(text, category) { if (this.activeTab && this.activeTab.traits.logInPage) { const warningFlag = 1; - this.activeTab.logInPage({ text, category, flags: warningFlag }); + this.activeTab.logInPage(text, category, warningFlag); } }, }; diff --git a/devtools/client/framework/test/browser_toolbox_target.js b/devtools/client/framework/test/browser_toolbox_target.js index 49df1d2fb9b8..c6e6941c9b25 100644 --- a/devtools/client/framework/test/browser_toolbox_target.js +++ b/devtools/client/framework/test/browser_toolbox_target.js @@ -37,7 +37,7 @@ add_task(async function() { const toolbox = await onToolboxReady; const onToolboxDestroyed = gDevTools.once("toolbox-destroyed"); - const onTabDetached = toolbox.target.activeTab.once("tabDetached"); + const onTabDetached = once(toolbox.target.client, "tabDetached"); info("Removing the iframes"); toolboxIframe.remove(); diff --git a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js index 55db7f501a64..66c26d8aed96 100644 --- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js +++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js @@ -115,6 +115,10 @@ function test() { todo(false, "Front for " + actor + " still held in pool!"); continue; } + // gcliActor is for the commandline which is separate to the toolbox + if (actor.includes("gcliActor")) { + continue; + } ok(false, "Front for " + actor + " still held in pool!"); } } diff --git a/devtools/client/framework/test/helper_disable_cache.js b/devtools/client/framework/test/helper_disable_cache.js index e8bc73e9236a..c3d62457a4a7 100644 --- a/devtools/client/framework/test/helper_disable_cache.js +++ b/devtools/client/framework/test/helper_disable_cache.js @@ -85,12 +85,11 @@ async function setDisableCacheCheckboxChecked(tabX, state) { if (cbx.checked !== state) { info("Setting disable cache checkbox to " + state + " for " + tabX.title); - const onReconfigured = tabX.toolbox.once("cache-reconfigured"); cbx.click(); - // We have to wait for the reconfigure request to be finished before reloading - // the page. - await onReconfigured; + // We need to wait for all checkboxes to be updated and the docshells to + // apply the new cache settings. + await waitForTick(); } } diff --git a/devtools/client/framework/toolbox-options.js b/devtools/client/framework/toolbox-options.js index c2f912949836..d74d2cddb807 100644 --- a/devtools/client/framework/toolbox-options.js +++ b/devtools/client/framework/toolbox-options.js @@ -460,7 +460,7 @@ OptionsPanel.prototype = { } if (this.target.activeTab && !this.target.chrome) { - const response = await this.target.activeTab.attach(); + const [ response ] = await this.target.client.attachTarget(this.target.activeTab._actor); this._origJavascriptEnabled = !response.javascriptEnabled; this.disableJSNode.checked = this._origJavascriptEnabled; this.disableJSNode.addEventListener("click", this._disableJSClicked); @@ -512,7 +512,7 @@ OptionsPanel.prototype = { "javascriptEnabled": !checked }; - this.target.activeTab.reconfigure({ options }); + this.target.activeTab.reconfigure(options); }, destroy: function() { diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index a0d215e647b0..e3a8682a870f 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -1339,21 +1339,12 @@ Toolbox.prototype = { * Apply the current cache setting from devtools.cache.disabled to this * toolbox's tab. */ - _applyCacheSettings: async function() { + _applyCacheSettings: function() { const pref = "devtools.cache.disabled"; const cacheDisabled = Services.prefs.getBoolPref(pref); if (this.target.activeTab) { - await this.target.activeTab.reconfigure({ - options: { - "cacheDisabled": cacheDisabled - } - }); - - // This event is only emitted for tests in order to know when to reload - if (flags.testing) { - this.emit("cache-reconfigured"); - } + this.target.activeTab.reconfigure({"cacheDisabled": cacheDisabled}); } }, @@ -1368,9 +1359,7 @@ Toolbox.prototype = { if (this.target.activeTab) { this.target.activeTab.reconfigure({ - options: { - "serviceWorkersTestingEnabled": serviceWorkersTestingEnabled - } + "serviceWorkersTestingEnabled": serviceWorkersTestingEnabled }); } }, @@ -1416,11 +1405,7 @@ Toolbox.prototype = { this.telemetry.toolClosed("paintflashing", this.sessionId, this); } this.isPaintFlashing = !this.isPaintFlashing; - return this.target.activeTab.reconfigure({ - options: { - "paintFlashing": this.isPaintFlashing - } - }); + return this.target.activeTab.reconfigure({"paintFlashing": this.isPaintFlashing}); }, /** @@ -2343,7 +2328,7 @@ Toolbox.prototype = { onSelectFrame: function(frameId) { // Send packet to the backend to select specified frame and // wait for 'frameUpdate' event packet to update the UI. - this.target.activeTab.switchToFrame({ windowId: frameId }); + this.target.activeTab.switchToFrame(frameId); }, /** diff --git a/devtools/client/inspector/test/browser_inspector_startup.js b/devtools/client/inspector/test/browser_inspector_startup.js index 5c4b45a94513..8441a75caf95 100644 --- a/devtools/client/inspector/test/browser_inspector_startup.js +++ b/devtools/client/inspector/test/browser_inspector_startup.js @@ -42,7 +42,7 @@ add_task(async function() { info("Navigate to the slow loading page"); const activeTab = inspector.toolbox.target.activeTab; - await activeTab.navigateTo({ url: TEST_URL }); + await activeTab.navigateTo(TEST_URL); info("Wait for request made to the image"); const response = await onRequest; diff --git a/devtools/client/inspector/test/head.js b/devtools/client/inspector/test/head.js index 6a21b94f883f..159948eb13a5 100644 --- a/devtools/client/inspector/test/head.js +++ b/devtools/client/inspector/test/head.js @@ -48,7 +48,7 @@ var navigateTo = async function(inspector, url) { info("Navigating to: " + url); const activeTab = inspector.toolbox.target.activeTab; - await activeTab.navigateTo({ url }); + await activeTab.navigateTo(url); info("Waiting for markup view to load after navigation."); await markuploaded; diff --git a/devtools/client/netmonitor/src/connector/firefox-connector.js b/devtools/client/netmonitor/src/connector/firefox-connector.js index 81f4bb7a6294..59dbbc15ef4b 100644 --- a/devtools/client/netmonitor/src/connector/firefox-connector.js +++ b/devtools/client/netmonitor/src/connector/firefox-connector.js @@ -316,7 +316,7 @@ class FirefoxConnector { // Reconfigures the tab, optionally triggering a reload. const reconfigureTab = options => { - return this.tabTarget.activeTab.reconfigure({ options }); + return this.tabTarget.activeTab.reconfigure(options); }; // Reconfigures the tab and waits for the target to finish navigating. diff --git a/devtools/client/netmonitor/test/head.js b/devtools/client/netmonitor/test/head.js index e0e2b80b1a86..01a1bbcc2e34 100644 --- a/devtools/client/netmonitor/test/head.js +++ b/devtools/client/netmonitor/test/head.js @@ -144,7 +144,7 @@ function toggleCache(target, disabled) { // Disable the cache for any toolbox that it is opened from this point on. Services.prefs.setBoolPref("devtools.cache.disabled", disabled); - return target.activeTab.reconfigure({ options }).then(() => navigationFinished); + return target.activeTab.reconfigure(options).then(() => navigationFinished); } /** diff --git a/devtools/client/shadereditor/test/head.js b/devtools/client/shadereditor/test/head.js index 6a97ffef7f49..0fdcb847ed07 100644 --- a/devtools/client/shadereditor/test/head.js +++ b/devtools/client/shadereditor/test/head.js @@ -131,7 +131,7 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate" } function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { - executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl })); + executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); return once(aTarget, aWaitForTargetEvent); } diff --git a/devtools/client/shared/test/browser_dbg_listtabs-03.js b/devtools/client/shared/test/browser_dbg_listtabs-03.js index 2d735b52ff0a..941c61f7a222 100644 --- a/devtools/client/shared/test/browser_dbg_listtabs-03.js +++ b/devtools/client/shared/test/browser_dbg_listtabs-03.js @@ -11,41 +11,51 @@ var { DebuggerServer } = require("devtools/server/main"); var { DebuggerClient } = require("devtools/shared/client/debugger-client"); +var { Task } = require("devtools/shared/task"); const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html"; -add_task(async function test() { +var gClient; + +function test() { DebuggerServer.init(); DebuggerServer.registerAllActors(); const transport = DebuggerServer.connectPipe(); - const client = new DebuggerClient(transport); - const [type] = await client.connect(); - is(type, "browser", "Root actor should identify itself as a browser."); - const tab = await addTab(TAB1_URL); + gClient = new DebuggerClient(transport); + gClient.connect().then(Task.async(function* ([aType, aTraits]) { + is(aType, "browser", + "Root actor should identify itself as a browser."); + const tab = yield addTab(TAB1_URL); - let { tabs } = await client.listTabs(); - is(tabs.length, 2, "Should be two tabs"); - const tabGrip = tabs.filter(a => a.url == TAB1_URL).pop(); - ok(tabGrip, "Should have an actor for the tab"); + let { tabs } = yield gClient.listTabs(); + is(tabs.length, 2, "Should be two tabs"); + const tabGrip = tabs.filter(a => a.url == TAB1_URL).pop(); + ok(tabGrip, "Should have an actor for the tab"); - let [response, targetFront] = await client.attachTarget(tabGrip.actor); - is(response.type, "tabAttached", "Should have attached"); + let response = yield gClient.request({ to: tabGrip.actor, type: "attach" }); + is(response.type, "tabAttached", "Should have attached"); - response = await client.listTabs(); - tabs = response.tabs; + response = yield gClient.listTabs(); + tabs = response.tabs; - response = await targetFront.detach(); - is(response.type, "detached", "Should have detached"); + response = yield gClient.request({ to: tabGrip.actor, type: "detach" }); + is(response.type, "detached", "Should have detached"); - const newGrip = tabs.filter(a => a.url == TAB1_URL).pop(); - is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab"); + const newGrip = tabs.filter(a => a.url == TAB1_URL).pop(); + is(newGrip.actor, tabGrip.actor, "Should have the same actor for the same tab"); - [response, targetFront] = await client.attachTarget(tabGrip.actor); - is(response.type, "tabAttached", "Should have attached"); - response = await targetFront.detach(); - is(response.type, "detached", "Should have detached"); + response = yield gClient.request({ to: tabGrip.actor, type: "attach" }); + is(response.type, "tabAttached", "Should have attached"); + response = yield gClient.request({ to: tabGrip.actor, type: "detach" }); + is(response.type, "detached", "Should have detached"); - await removeTab(tab); - await client.close(); + yield removeTab(tab); + yield gClient.close(); + finish(); + })); +} + +registerCleanupFunction(function() { + gClient = null; }); diff --git a/devtools/client/shared/test/browser_dbg_navigation.js b/devtools/client/shared/test/browser_dbg_navigation.js index 53a77fceadf9..a7bc37249e33 100644 --- a/devtools/client/shared/test/browser_dbg_navigation.js +++ b/devtools/client/shared/test/browser_dbg_navigation.js @@ -39,10 +39,10 @@ function test() { }); } -function testNavigate(targetFront) { +function testNavigate([aGrip, aResponse]) { const outstanding = [promise.defer(), promise.defer()]; - targetFront.on("tabNavigated", function onTabNavigated(packet) { + gClient.addListener("tabNavigated", function onTabNavigated(event, packet) { is(packet.url.split("/").pop(), TAB2_FILE, "Got a tab navigation notification."); @@ -54,27 +54,27 @@ function testNavigate(targetFront) { outstanding[0].resolve(); } else { ok(true, "Tab finished navigating."); - targetFront.off("tabNavigated", onTabNavigated); + gClient.removeListener("tabNavigated", onTabNavigated); outstanding[1].resolve(); } }); BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TAB2_URL); return promise.all(outstanding.map(e => e.promise)) - .then(() => targetFront); + .then(() => aGrip.actor); } -async function testDetach(targetFront) { - const onDetached = targetFront.once("tabDetached"); +function testDetach(actor) { + const deferred = promise.defer(); + + gClient.addOneTimeListener("tabDetached", (type, packet) => { + ok(true, "Got a tab detach notification."); + is(packet.from, actor, "tab detach message comes from the expected actor"); + deferred.resolve(gClient.close()); + }); removeTab(gBrowser.selectedTab); - - const packet = await onDetached; - ok(true, "Got a tab detach notification."); - is(packet.from, targetFront.actorID, - "tab detach message comes from the expected actor"); - - return gClient.close(); + return deferred.promise; } registerCleanupFunction(function() { @@ -83,8 +83,8 @@ registerCleanupFunction(function() { async function attachTargetActorForUrl(client, url) { const grip = await getTargetActorForUrl(client, url); - const [, targetFront] = await client.attachTarget(grip.actor); - return targetFront; + const [ response ] = await client.attachTarget(grip.actor); + return [grip, response]; } function getTargetActorForUrl(client, url) { diff --git a/devtools/client/webaudioeditor/test/head.js b/devtools/client/webaudioeditor/test/head.js index 08cf88aa55bc..1680e3b7ce12 100644 --- a/devtools/client/webaudioeditor/test/head.js +++ b/devtools/client/webaudioeditor/test/head.js @@ -48,7 +48,7 @@ function reload(aTarget, aWaitForTargetEvent = "navigate") { } function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") { - executeSoon(() => aTarget.activeTab.navigateTo({ url: aUrl })); + executeSoon(() => aTarget.activeTab.navigateTo(aUrl)); return once(aTarget, aWaitForTargetEvent); } diff --git a/devtools/client/webide/modules/tab-store.js b/devtools/client/webide/modules/tab-store.js index 8429f524ba72..aed0a7223cf7 100644 --- a/devtools/client/webide/modules/tab-store.js +++ b/devtools/client/webide/modules/tab-store.js @@ -61,11 +61,15 @@ TabStore.prototype = { // Watch for changes to remote browser tabs this._connection.client.addListener("tabListChanged", this._onTabListChanged); + this._connection.client.addListener("tabNavigated", + this._onTabNavigated); this.listTabs(); } else { if (this._connection.client) { this._connection.client.removeListener("tabListChanged", this._onTabListChanged); + this._connection.client.removeListener("tabNavigated", + this._onTabNavigated); } this._resetStore(); } diff --git a/devtools/docs/backend/client-api.md b/devtools/docs/backend/client-api.md index cd843fcac275..89c889aa8f2a 100644 --- a/devtools/docs/backend/client-api.md +++ b/devtools/docs/backend/client-api.md @@ -21,6 +21,8 @@ function start() { // Start the client. client = new DebuggerClient(transport); + // Attach listeners for client events. + client.addListener("tabNavigated", onTab); client.connect((type, traits) => { // Now the client is conected to the server. debugTab(); @@ -49,6 +51,9 @@ async function startClient() { // Start the client. client = new DebuggerClient(transport); + // Attach listeners for client events. + client.addListener("tabNavigated", onTab); + client.connect((type, traits) => { // Now the client is conected to the server. debugTab(); @@ -84,9 +89,6 @@ function attachToTab() { } // Now the tabClient is ready and can be used. - - // Attach listeners for client events. - tabClient.addListener("tabNavigated", onTab); }); }); } @@ -103,7 +105,7 @@ async function onTab() { // Detach from the previous thread. await client.activeThread.detach(); // Detach from the previous tab. - await tabClient.activeTab.detach(); + await client.activeTab.detach(); // Start debugging the new tab. start(); } @@ -167,6 +169,8 @@ function startDebugger() { // Start the client. client = new DebuggerClient(transport); + // Attach listeners for client events. + client.addListener("tabNavigated", onTab); client.connect((type, traits) => { // Now the client is conected to the server. debugTab(); diff --git a/devtools/server/actors/targets/browsing-context.js b/devtools/server/actors/targets/browsing-context.js index 51402370cfae..c9d10e93dac0 100644 --- a/devtools/server/actors/targets/browsing-context.js +++ b/devtools/server/actors/targets/browsing-context.js @@ -966,7 +966,7 @@ const browsingContextTargetPrototype = { // subsequent navigation event packet. Services.tm.dispatchToMainThread(DevToolsUtils.makeInfallible(() => { this.window.location = request.url; - }, "BrowsingContextTargetActor.prototype.navigateTo's delayed body:" + request.url)); + }, "BrowsingContextTargetActor.prototype.navigateTo's delayed body")); return {}; }, diff --git a/devtools/server/tests/browser/browser_navigateEvents.js b/devtools/server/tests/browser/browser_navigateEvents.js index 974b85ee06f7..bdb314f0fc3d 100644 --- a/devtools/server/tests/browser/browser_navigateEvents.js +++ b/devtools/server/tests/browser/browser_navigateEvents.js @@ -102,12 +102,12 @@ async function connectAndAttachTab() { // Connect to this tab const transport = DebuggerServer.connectPipe(); const client = new DebuggerClient(transport); - const form = await connectDebuggerClient(client); - const actorID = form.actor; - const [, targetFront ] = await client.attachTarget(actorID); - targetFront.on("tabNavigated", function(packet) { + client.addListener("tabNavigated", function(event, packet) { assertEvent("tabNavigated", packet); }); + const form = await connectDebuggerClient(client); + const actorID = form.actor; + await client.attachTarget(actorID); return { client, actorID }; } diff --git a/devtools/server/tests/browser/browser_webextension_inspected_window.js b/devtools/server/tests/browser/browser_webextension_inspected_window.js index d642116a049a..502543e3ac58 100644 --- a/devtools/server/tests/browser/browser_webextension_inspected_window.js +++ b/devtools/server/tests/browser/browser_webextension_inspected_window.js @@ -26,7 +26,7 @@ async function setup(pageUrl) { const { client, form } = target; - const [, targetFront] = await client.attachTarget(form.actor); + const [, tabClient] = await client.attachTarget(form.actor); const [, consoleClient] = await client.attachConsole(form.consoleActor, []); @@ -34,7 +34,7 @@ async function setup(pageUrl) { return { client, form, - targetFront, consoleClient, + tabClient, consoleClient, inspectedWindowFront, extension, fakeExtCallerInfo, }; @@ -47,11 +47,11 @@ async function teardown({client, extension}) { await extension.unload(); } -function waitForNextTabNavigated(targetFront) { +function waitForNextTabNavigated(client) { return new Promise(resolve => { - targetFront.on("tabNavigated", function tabNavigatedListener(pkt) { + client.addListener("tabNavigated", function tabNavigatedListener(evt, pkt) { if (pkt.state == "stop" && !pkt.isFrameSwitching) { - targetFront.off("tabNavigated", tabNavigatedListener); + client.removeListener("tabNavigated", tabNavigatedListener); resolve(); } }); @@ -227,12 +227,12 @@ add_task(async function test_exception_inspectedWindowEval_result() { add_task(async function test_exception_inspectedWindowReload() { const { client, consoleClient, inspectedWindowFront, - extension, fakeExtCallerInfo, targetFront, + extension, fakeExtCallerInfo, } = await setup(`${TEST_RELOAD_URL}?test=cache`); // Test reload with bypassCache=false. - const waitForNoBypassCacheReload = waitForNextTabNavigated(targetFront); + const waitForNoBypassCacheReload = waitForNextTabNavigated(client); const reloadResult = await inspectedWindowFront.reload(fakeExtCallerInfo, {ignoreCache: false}); @@ -248,7 +248,7 @@ add_task(async function test_exception_inspectedWindowReload() { // Test reload with bypassCache=true. - const waitForForceBypassCacheReload = waitForNextTabNavigated(targetFront); + const waitForForceBypassCacheReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {ignoreCache: true}); await waitForForceBypassCacheReload; @@ -265,12 +265,12 @@ add_task(async function test_exception_inspectedWindowReload() { add_task(async function test_exception_inspectedWindowReload_customUserAgent() { const { client, consoleClient, inspectedWindowFront, - extension, fakeExtCallerInfo, targetFront, + extension, fakeExtCallerInfo, } = await setup(`${TEST_RELOAD_URL}?test=user-agent`); // Test reload with custom userAgent. - const waitForCustomUserAgentReload = waitForNextTabNavigated(targetFront); + const waitForCustomUserAgentReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {userAgent: "Customized User Agent"}); @@ -284,7 +284,7 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() { // Test reload with no custom userAgent. - const waitForNoCustomUserAgentReload = waitForNextTabNavigated(targetFront); + const waitForNoCustomUserAgentReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {}); await waitForNoCustomUserAgentReload; @@ -301,12 +301,12 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() { add_task(async function test_exception_inspectedWindowReload_injectedScript() { const { client, consoleClient, inspectedWindowFront, - extension, fakeExtCallerInfo, targetFront, + extension, fakeExtCallerInfo, } = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`); // Test reload with an injectedScript. - const waitForInjectedScriptReload = waitForNextTabNavigated(targetFront); + const waitForInjectedScriptReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {injectedScript: `new ${injectedScript}`}); await waitForInjectedScriptReload; @@ -321,7 +321,7 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() { // Test reload without an injectedScript. - const waitForNoInjectedScriptReload = waitForNextTabNavigated(targetFront); + const waitForNoInjectedScriptReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {}); await waitForNoInjectedScriptReload; @@ -339,13 +339,13 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() { add_task(async function test_exception_inspectedWindowReload_multiple_calls() { const { client, consoleClient, inspectedWindowFront, - extension, fakeExtCallerInfo, targetFront, + extension, fakeExtCallerInfo, } = await setup(`${TEST_RELOAD_URL}?test=user-agent`); // Test reload with custom userAgent three times (and then // check that only the first one has affected the page reload. - const waitForCustomUserAgentReload = waitForNextTabNavigated(targetFront); + const waitForCustomUserAgentReload = waitForNextTabNavigated(client); inspectedWindowFront.reload(fakeExtCallerInfo, {userAgent: "Customized User Agent 1"}); inspectedWindowFront.reload(fakeExtCallerInfo, {userAgent: "Customized User Agent 2"}); @@ -360,7 +360,7 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() { // Test reload with no custom userAgent. - const waitForNoCustomUserAgentReload = waitForNextTabNavigated(targetFront); + const waitForNoCustomUserAgentReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {}); await waitForNoCustomUserAgentReload; @@ -377,12 +377,12 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() { add_task(async function test_exception_inspectedWindowReload_stopped() { const { client, consoleClient, inspectedWindowFront, - extension, fakeExtCallerInfo, targetFront, + extension, fakeExtCallerInfo, } = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`); // Test reload on a page that calls window.stop() immediately during the page loading - const waitForPageLoad = waitForNextTabNavigated(targetFront); + const waitForPageLoad = waitForNextTabNavigated(client); await inspectedWindowFront.eval(fakeExtCallerInfo, "window.location += '&stop=windowStop'"); @@ -390,7 +390,7 @@ add_task(async function test_exception_inspectedWindowReload_stopped() { await waitForPageLoad; info("Starting a reload with an injectedScript"); - const waitForInjectedScriptReload = waitForNextTabNavigated(targetFront); + const waitForInjectedScriptReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {injectedScript: `new ${injectedScript}`}); await waitForInjectedScriptReload; @@ -408,7 +408,7 @@ add_task(async function test_exception_inspectedWindowReload_stopped() { // Reload again with no options. info("Reload the tab again without any reload options"); - const waitForNoInjectedScriptReload = waitForNextTabNavigated(targetFront); + const waitForNoInjectedScriptReload = waitForNextTabNavigated(client); await inspectedWindowFront.reload(fakeExtCallerInfo, {}); await waitForNoInjectedScriptReload; diff --git a/devtools/server/tests/mochitest/test_webextension-addon-debugging-connect.html b/devtools/server/tests/mochitest/test_webextension-addon-debugging-connect.html index 7d41b9daeaa6..816e9b3b3153 100644 --- a/devtools/server/tests/mochitest/test_webextension-addon-debugging-connect.html +++ b/devtools/server/tests/mochitest/test_webextension-addon-debugging-connect.html @@ -42,6 +42,7 @@ async function test_connect_addon(oopMode) { ok(addonTargetActor, "The expected webextension addon actor has been found"); // Connect to the target addon actor and wait for the updated list of frames. + const waitFramesUpdated = waitForFramesUpdated({client}); const addonTarget = await TargetFactory.forRemoteTab({ form: addonTargetActor, client, @@ -49,7 +50,7 @@ async function test_connect_addon(oopMode) { }); is(addonTarget.form.isOOP, oopMode, "Got the expected oop mode in the webextension actor form"); - const frames = await waitForFramesUpdated(addonTarget); + const frames = await waitFramesUpdated; const backgroundPageFrame = frames.filter((frame) => { return frame.url && frame.url.endsWith("/_generated_background_page.html"); }).pop(); diff --git a/devtools/server/tests/mochitest/webextension-helpers.js b/devtools/server/tests/mochitest/webextension-helpers.js index ab180044031b..29e465069953 100644 --- a/devtools/server/tests/mochitest/webextension-helpers.js +++ b/devtools/server/tests/mochitest/webextension-helpers.js @@ -51,19 +51,19 @@ function setWebExtensionOOPMode(oopMode) { }); } -function waitForFramesUpdated(target, matchFn) { +function waitForFramesUpdated({client}, matchFn) { return new Promise(resolve => { - const listener = data => { + const listener = (evt, data) => { if (typeof matchFn === "function" && !matchFn(data)) { return; } else if (!data.frames) { return; } - target.activeTab.off("frameUpdate", listener); + client.removeListener("frameUpdate", listener); resolve(data.frames); }; - target.activeTab.on("frameUpdate", listener); + client.addListener("frameUpdate", listener); }); } diff --git a/devtools/server/tests/unit/test_sourcemaps-01.js b/devtools/server/tests/unit/test_sourcemaps-01.js index fe0b7f74aee2..8c59d2d488ab 100644 --- a/devtools/server/tests/unit/test_sourcemaps-01.js +++ b/devtools/server/tests/unit/test_sourcemaps-01.js @@ -44,7 +44,7 @@ function test_simple_source_map() { expectedSources.delete(packet.source.url); if (expectedSources.size === 0) { - gThreadClient.removeListener("newSource", _onNewSource); + gClient.removeListener("newSource", _onNewSource); finishClient(gClient); } }); diff --git a/devtools/shared/client/constants.js b/devtools/shared/client/constants.js index ef016cf1d8cd..ccf4605240b4 100644 --- a/devtools/shared/client/constants.js +++ b/devtools/shared/client/constants.js @@ -33,16 +33,13 @@ const UnsolicitedNotifications = { "addonListChanged": "addonListChanged", "workerListChanged": "workerListChanged", "serviceWorkerRegistrationListChanged": "serviceWorkerRegistrationList", + "tabNavigated": "tabNavigated", + "frameUpdate": "frameUpdate", "pageError": "pageError", "evaluationResult": "evaluationResult", - "updatedSource": "updatedSource", - "inspectObject": "inspectObject", - - // newSource is still emitted on the ThreadActor, in addition to the - // BrowsingContextActor we have to keep it here until ThreadClient is converted to - // ThreadFront and/or we stop emitting this duplicated events. - // See ThreadActor.onNewSourceEvent. "newSource": "newSource", + "updatedSource": "updatedSource", + "inspectObject": "inspectObject" }; /** diff --git a/devtools/shared/client/debugger-client.js b/devtools/shared/client/debugger-client.js index 8f781ea1427c..af15188bfdad 100644 --- a/devtools/shared/client/debugger-client.js +++ b/devtools/shared/client/debugger-client.js @@ -24,11 +24,10 @@ loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter"); loader.lazyRequireGetter(this, "WebConsoleClient", "devtools/shared/webconsole/client", true); loader.lazyRequireGetter(this, "AddonClient", "devtools/shared/client/addon-client"); loader.lazyRequireGetter(this, "RootClient", "devtools/shared/client/root-client"); -loader.lazyRequireGetter(this, "BrowsingContextFront", "devtools/shared/fronts/targets/browsing-context", true); +loader.lazyRequireGetter(this, "TabClient", "devtools/shared/client/tab-client"); loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client"); loader.lazyRequireGetter(this, "WorkerClient", "devtools/shared/client/worker-client"); loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client"); -loader.lazyRequireGetter(this, "Pool", "devtools/shared/protocol", true); // Retrieve the major platform version, i.e. if we are on Firefox 64.0a1, it will be 64. const PLATFORM_MAJOR_VERSION = AppConstants.MOZ_APP_VERSION.match(/\d+/)[0]; @@ -51,19 +50,8 @@ function DebuggerClient(transport) { this._transport.hooks = this; // Map actor ID to client instance for each actor type. - // To be removed once all clients are refactored to protocol.js this._clients = new Map(); - // Pool of fronts instanciated by this class. - // This is useful for actors that have already been transitioned to protocol.js - // Once RootClient becomes a protocol.js actor, these actors can be attached to it - // instead of this pool. - // This Pool will automatically be added to this._pools via addActorPool once the first - // Front will be added to it (in attachTarget, attachWorker,...). - // And it does not need to destroyed explicitly as all Pools are destroyed on client - // closing. - this._frontPool = new Pool(this); - this._pendingRequests = new Map(); this._activeRequests = new Map(); this._eventsEnabled = true; @@ -296,9 +284,7 @@ DebuggerClient.prototype = { this._eventsEnabled = false; const cleanup = () => { - if (this._transport) { - this._transport.close(); - } + this._transport.close(); this._transport = null; }; @@ -368,15 +354,29 @@ DebuggerClient.prototype = { * @param string targetActor * The target actor ID for the tab to attach. */ - attachTarget: async function(targetActor) { - let front = this._frontPool.actor(targetActor); - if (!front) { - front = new BrowsingContextFront(this, { actor: targetActor }); - this._frontPool.manage(front); + attachTarget: function(targetActor) { + if (this._clients.has(targetActor)) { + const cachedTarget = this._clients.get(targetActor); + const cachedResponse = { + cacheDisabled: cachedTarget.cacheDisabled, + javascriptEnabled: cachedTarget.javascriptEnabled, + traits: cachedTarget.traits, + }; + return promise.resolve([cachedResponse, cachedTarget]); } - const response = await front.attach(); - return [response, front]; + const packet = { + to: targetActor, + type: "attach" + }; + return this.request(packet).then(response => { + // TabClient can actually represent targets other than a tab. + // It is planned to be renamed while being converted to a front + // in bug 1485660. + const targetClient = new TabClient(this, response); + this.registerClient(targetClient); + return [response, targetClient]; + }); }, attachWorker: function(workerTargetActor) { diff --git a/devtools/shared/client/moz.build b/devtools/shared/client/moz.build index 3fa90f38dc4b..a7b28a798437 100644 --- a/devtools/shared/client/moz.build +++ b/devtools/shared/client/moz.build @@ -19,6 +19,7 @@ DevToolsModules( 'root-client.js', 'source-client.js', 'symbol-iterator-client.js', + 'tab-client.js', 'thread-client.js', 'worker-client.js', ) diff --git a/devtools/shared/client/tab-client.js b/devtools/shared/client/tab-client.js new file mode 100644 index 000000000000..0936853a7ae9 --- /dev/null +++ b/devtools/shared/client/tab-client.js @@ -0,0 +1,163 @@ +/* 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 promise = require("devtools/shared/deprecated-sync-thenables"); + +const eventSource = require("devtools/shared/client/event-source"); +const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); +loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client"); + +/** + * Creates a tab client for the remote debugging protocol server. This client is a front + * to the target actor for a tab created in the server side, hiding the protocol details + * in a traditional JavaScript API. + * + * @param client DebuggerClient + * The debugger client parent. + * @param form object + * The protocol form for this tab. + */ +function TabClient(client, form) { + this.client = client; + this._actor = form.from; + this._threadActor = form.threadActor; + this.javascriptEnabled = form.javascriptEnabled; + this.cacheDisabled = form.cacheDisabled; + this.thread = null; + this.request = this.client.request; + this.traits = form.traits || {}; + this.events = ["workerListChanged"]; +} + +TabClient.prototype = { + get actor() { + return this._actor; + }, + get _transport() { + return this.client._transport; + }, + + /** + * Attach to a thread actor. + * + * @param object options + * Configuration options. + * - useSourceMaps: whether to use source maps or not. + */ + attachThread: function(options = {}) { + if (this.thread) { + return promise.resolve([{}, this.thread]); + } + + const packet = { + to: this._threadActor, + type: "attach", + options, + }; + return this.request(packet).then(response => { + this.thread = new ThreadClient(this, this._threadActor); + this.client.registerClient(this.thread); + return [response, this.thread]; + }); + }, + + /** + * Detach the client from the target actor. + */ + detach: DebuggerClient.requester({ + type: "detach" + }, { + before: function(packet) { + if (this.thread) { + this.thread.detach(); + } + return packet; + }, + after: function(response) { + this.client.unregisterClient(this); + return response; + }, + }), + + /** + * Bring the window to the front. + */ + focus: DebuggerClient.requester({ + type: "focus" + }, {}), + + /** + * Ensure relevant pages have error reporting enabled. + */ + ensureCSSErrorReportingEnabled: DebuggerClient.requester({ + type: "ensureCSSErrorReportingEnabled", + }, {}), + + /** + * Reload the page in this tab. + * + * @param [optional] object options + * An object with a `force` property indicating whether or not + * this reload should skip the cache + */ + reload: function(options = { force: false }) { + return this._reload(options); + }, + _reload: DebuggerClient.requester({ + type: "reload", + options: arg(0) + }), + + /** + * Navigate to another URL. + * + * @param string url + * The URL to navigate to. + */ + navigateTo: DebuggerClient.requester({ + type: "navigateTo", + url: arg(0) + }), + + /** + * Reconfigure the target actor. + * + * @param object options + * A dictionary object of the new options to use in the target actor. + */ + reconfigure: DebuggerClient.requester({ + type: "reconfigure", + options: arg(0) + }), + + listWorkers: DebuggerClient.requester({ + type: "listWorkers" + }), + + attachWorker: function(workerTargetActor) { + return this.client.attachWorker(workerTargetActor); + }, + + logInPage: DebuggerClient.requester({ + type: "logInPage", + text: arg(0), + category: arg(1), + flags: arg(2), + }), + + listFrames: DebuggerClient.requester({ + type: "listFrames", + }), + + switchToFrame: DebuggerClient.requester({ + type: "switchToFrame", + windowId: arg(0), + }), +}; + +eventSource(TabClient.prototype); + +module.exports = TabClient; diff --git a/devtools/shared/client/thread-client.js b/devtools/shared/client/thread-client.js index 76b6e9e2a978..4c159bbf10bc 100644 --- a/devtools/shared/client/thread-client.js +++ b/devtools/shared/client/thread-client.js @@ -25,7 +25,7 @@ const noop = () => {}; * is a front to the thread actor created in the server side, hiding the * protocol details in a traditional JavaScript API. * - * @param client DebuggerClient, WorkerClient or BrowsingContextFront + * @param client DebuggerClient|TabClient * The parent of the thread (tab for target-scoped debuggers, * DebuggerClient for chrome debuggers). * @param actor string diff --git a/devtools/shared/fronts/moz.build b/devtools/shared/fronts/moz.build index 202b31344f97..3a02c4f9ede9 100644 --- a/devtools/shared/fronts/moz.build +++ b/devtools/shared/fronts/moz.build @@ -6,7 +6,6 @@ DIRS += [ 'addon', - 'targets', ] DevToolsModules( diff --git a/devtools/shared/fronts/targets/browsing-context.js b/devtools/shared/fronts/targets/browsing-context.js deleted file mode 100644 index 7a692b1cd6ed..000000000000 --- a/devtools/shared/fronts/targets/browsing-context.js +++ /dev/null @@ -1,88 +0,0 @@ -/* 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 {browsingContextTargetSpec} = require("devtools/shared/specs/targets/browsing-context"); -const protocol = require("devtools/shared/protocol"); -const {custom} = protocol; - -loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client"); - -const BrowsingContextFront = protocol.FrontClassWithSpec(browsingContextTargetSpec, { - initialize: function(client, form) { - protocol.Front.prototype.initialize.call(this, client, form); - - this.thread = null; - - // TODO: remove once ThreadClient becomes a front - this.client = client; - }, - - /** - * Attach to a thread actor. - * - * @param object options - * Configuration options. - * - useSourceMaps: whether to use source maps or not. - */ - attachThread: function(options = {}) { - if (this.thread) { - return Promise.resolve([{}, this.thread]); - } - - const packet = { - to: this._threadActor, - type: "attach", - options, - }; - return this.client.request(packet).then(response => { - this.thread = new ThreadClient(this, this._threadActor); - this.client.registerClient(this.thread); - return [response, this.thread]; - }); - }, - - attach: custom(async function() { - const response = await this._attach(); - - this._threadActor = response.threadActor; - this.javascriptEnabled = response.javascriptEnabled; - this.cacheDisabled = response.cacheDisabled; - this.traits = response.traits || {}; - - return response; - }, { - impl: "_attach" - }), - - detach: custom(async function() { - let response; - try { - response = await this._detach(); - } catch (e) { - console.warn( - `Error while detaching the browsing context target front: ${e.message}`); - } - - if (this.thread) { - try { - await this.thread.detach(); - } catch (e) { - console.warn(`Error while detaching the thread front: ${e.message}`); - } - } - - this.destroy(); - - return response; - }, { - impl: "_detach" - }), - - attachWorker: function(workerTargetActor) { - return this.client.attachWorker(workerTargetActor); - }, -}); - -exports.BrowsingContextFront = BrowsingContextFront; diff --git a/devtools/shared/fronts/targets/moz.build b/devtools/shared/fronts/targets/moz.build deleted file mode 100644 index cd66f4e661c7..000000000000 --- a/devtools/shared/fronts/targets/moz.build +++ /dev/null @@ -1,9 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -DevToolsModules( - 'browsing-context.js', -) diff --git a/devtools/shared/protocol.js b/devtools/shared/protocol.js index 338fb8eacd72..58dbeb4f6c4e 100644 --- a/devtools/shared/protocol.js +++ b/devtools/shared/protocol.js @@ -1352,10 +1352,7 @@ Front.prototype = extend(Pool.prototype, { } else { this.actor().then(actorID => { packet.to = actorID; - // The connection might be closed during the promise resolution - if (this.conn._transport) { - this.conn._transport.send(packet); - } + this.conn._transport.send(packet); }).catch(console.error); } }, diff --git a/devtools/shared/specs/targets/browsing-context.js b/devtools/shared/specs/targets/browsing-context.js index 9d7c902a7837..02f6a6875662 100644 --- a/devtools/shared/specs/targets/browsing-context.js +++ b/devtools/shared/specs/targets/browsing-context.js @@ -127,17 +127,10 @@ const browsingContextTargetSpecPrototype = { destroyAll: Option(0, "nullable:boolean") }, tabDetached: { - type: "tabDetached", - // This is to make browser_dbg_navigation.js to work as it expect to - // see a packet object when listening for tabDetached - from: Option(0, "string"), + type: "tabDetached" }, workerListChanged: { type: "workerListChanged" - }, - newSource: { - type: "newSource", - source: Option(0, "json") } } };