From 28a8d4a224ca2fdbfaeb2b2dd80a7e01ee68a171 Mon Sep 17 00:00:00 2001 From: Panos Astithas Date: Wed, 11 Jul 2012 14:43:11 +0300 Subject: [PATCH] Bug 751226 - Refactor all the existing browser actor implementations to eliminate duplication. r=rcampbell r=mark.finkle r=21 --- b2g/chrome/content/dbg-browser-actors.js | 350 ++++--------- b2g/chrome/content/shell.js | 1 + mobile/android/chrome/content/browser.js | 1 + .../chrome/content/dbg-browser-actors.js | 476 +++--------------- .../debugger/server/dbg-browser-actors.js | 17 +- 5 files changed, 183 insertions(+), 662 deletions(-) diff --git a/b2g/chrome/content/dbg-browser-actors.js b/b2g/chrome/content/dbg-browser-actors.js index 185369f8e5e..07f72e4658d 100644 --- a/b2g/chrome/content/dbg-browser-actors.js +++ b/b2g/chrome/content/dbg-browser-actors.js @@ -5,6 +5,10 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; +/** + * B2G-specific actors that extend BrowserRootActor and BrowserTabActor, + * overriding some of their methods. + */ /** * The function that creates the root actor. DebuggerServer expects to find this @@ -24,67 +28,52 @@ function createRootActor(connection) { * The conection to the client. */ function DeviceRootActor(connection) { - this.conn = connection; - this._tabActors = new WeakMap(); - this._tabActorPool = null; - this._actorFactories = null; + BrowserRootActor.call(this, connection); this.browser = Services.wm.getMostRecentWindow('navigator:browser'); } -DeviceRootActor.prototype = { - /** - * Return a 'hello' packet as specified by the Remote Debugging Protocol. - */ - sayHello: function DRA_sayHello() { - return { - from: 'root', - applicationType: 'browser', - traits: [] - }; - }, +DeviceRootActor.prototype = new BrowserRootActor(); - /** - * Disconnects the actor from the browser window. - */ - disconnect: function DRA_disconnect() { - let actor = this._tabActors.get(this.browser); - if (actor) { - actor.exit(); - } - }, +/** + * Disconnects the actor from the browser window. + */ +DeviceRootActor.prototype.disconnect = function DRA_disconnect() { + let actor = this._tabActors.get(this.browser); + if (actor) { + actor.exit(); + } +}; - /** - * Handles the listTabs request. Builds a list of actors for the single - * tab (window) running in the process. The actors will survive - * until at least the next listTabs request. - */ - onListTabs: function DRA_onListTabs() { - let actor = this._tabActors.get(this.browser); - if (!actor) { - actor = new DeviceTabActor(this.conn, this.browser); - // this.actorID is set by ActorPool when an actor is put into one. - actor.parentID = this.actorID; - this._tabActors.set(this.browser, actor); - } - - let actorPool = new ActorPool(this.conn); - actorPool.addActor(actor); - - // Now drop the old actorID -> actor map. Actors that still mattered were - // added to the new map, others will go away. - if (this._tabActorPool) { - this.conn.removeActorPool(this._tabActorPool); - } - this._tabActorPool = actorPool; - this.conn.addActorPool(this._tabActorPool); - - return { - 'from': 'root', - 'selected': 0, - 'tabs': [actor.grip()] - }; +/** + * Handles the listTabs request. Builds a list of actors for the single + * tab (window) running in the process. The actors will survive + * until at least the next listTabs request. + */ +DeviceRootActor.prototype.onListTabs = function DRA_onListTabs() { + let actor = this._tabActors.get(this.browser); + if (!actor) { + actor = new DeviceTabActor(this.conn, this.browser); + // this.actorID is set by ActorPool when an actor is put into one. + actor.parentID = this.actorID; + this._tabActors.set(this.browser, actor); } + let actorPool = new ActorPool(this.conn); + actorPool.addActor(actor); + + // Now drop the old actorID -> actor map. Actors that still mattered were + // added to the new map, others will go away. + if (this._tabActorPool) { + this.conn.removeActorPool(this._tabActorPool); + } + this._tabActorPool = actorPool; + this.conn.addActorPool(this._tabActorPool); + + return { + 'from': 'root', + 'selected': 0, + 'tabs': [actor.grip()] + }; }; /** @@ -104,219 +93,58 @@ DeviceRootActor.prototype.requestTypes = { * The browser instance that contains this tab. */ function DeviceTabActor(connection, browser) { - this.conn = connection; - this._browser = browser; + BrowserTabActor.call(this, connection, browser); } -DeviceTabActor.prototype = { - get browser() { - return this._browser; - }, +DeviceTabActor.prototype = new BrowserTabActor(); - get exited() { - return !this.browser; - }, - - get attached() { - return !!this._attached - }, - - _tabPool: null, - get tabActorPool() { - return this._tabPool; - }, - - _contextPool: null, - get contextActorPool() { - return this._contextPool; - }, - - /** - * Add the specified breakpoint to the default actor pool connection, in order - * to be alive as long as the server is. - * - * @param BreakpointActor actor - * The actor object. - */ - addToBreakpointPool: function DTA_addToBreakpointPool(actor) { - this.conn.addActor(actor); - }, - - /** - * Remove the specified breakpint from the default actor pool. - * - * @param string actor - * The actor ID. - */ - removeFromBreakpointPool: function DTA_removeFromBreakpointPool(actor) { - this.conn.removeActor(actor); - }, - - actorPrefix: 'tab', - - grip: function DTA_grip() { - dbg_assert(!this.exited, - 'grip() should not be called on exited browser actor.'); - dbg_assert(this.actorID, - 'tab should have an actorID.'); - return { - 'actor': this.actorID, - 'title': this.browser.title, - 'url': this.browser.document.documentURI - } - }, - - /** - * Called when the actor is removed from the connection. - */ - disconnect: function DTA_disconnect() { - this._detach(); - }, - - /** - * Called by the root actor when the underlying tab is closed. - */ - exit: function DTA_exit() { - if (this.exited) { - return; - } - - if (this.attached) { - this._detach(); - this.conn.send({ - 'from': this.actorID, - 'type': 'tabDetached' - }); - } - - this._browser = null; - }, - - /** - * Does the actual work of attaching to a tab. - */ - _attach: function DTA_attach() { - if (this._attached) { - return; - } - - // Create a pool for tab-lifetime actors. - dbg_assert(!this._tabPool, 'Should not have a tab pool if we were not attached.'); - this._tabPool = new ActorPool(this.conn); - this.conn.addActorPool(this._tabPool); - - // ... and a pool for context-lifetime actors. - this._pushContext(); - - this._attached = true; - }, - - /** - * Creates a thread actor and a pool for context-lifetime actors. It then sets - * up the content window for debugging. - */ - _pushContext: function DTA_pushContext() { - dbg_assert(!this._contextPool, "Can't push multiple contexts"); - - this._contextPool = new ActorPool(this.conn); - this.conn.addActorPool(this._contextPool); - - this.threadActor = new ThreadActor(this); - this._addDebuggees(this.browser.wrappedJSObject); - this._contextPool.addActor(this.threadActor); - }, - - /** - * Add the provided window and all windows in its frame tree as debuggees. - */ - _addDebuggees: function DTA__addDebuggees(content) { - this.threadActor.addDebuggee(content); - let frames = content.frames; - for (let i = 0; i < frames.length; i++) { - this._addDebuggees(frames[i]); - } - }, - - /** - * Exits the current thread actor and removes the context-lifetime actor pool. - * The content window is no longer being debugged after this call. - */ - _popContext: function DTA_popContext() { - dbg_assert(!!this._contextPool, 'No context to pop.'); - - this.conn.removeActorPool(this._contextPool); - this._contextPool = null; - this.threadActor.exit(); - this.threadActor = null; - }, - - /** - * Does the actual work of detaching from a tab. - */ - _detach: function DTA_detach() { - if (!this.attached) { - return; - } - - this._popContext(); - - // Shut down actors that belong to this tab's pool. - this.conn.removeActorPool(this._tabPool); - this._tabPool = null; - - this._attached = false; - }, - - // Protocol Request Handlers - - onAttach: function DTA_onAttach(aRequest) { - if (this.exited) { - return { type: 'exited' }; - } - - this._attach(); - - return { type: 'tabAttached', threadActor: this.threadActor.actorID }; - }, - - onDetach: function DTA_onDetach(aRequest) { - if (!this.attached) { - return { error: 'wrongState' }; - } - - this._detach(); - - return { type: 'detached' }; - }, - - /** - * Prepare to enter a nested event loop by disabling debuggee events. - */ - preNest: function DTA_preNest() { - let windowUtils = this.browser - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.suppressEventHandling(true); - windowUtils.suspendTimeouts(); - }, - - /** - * Prepare to exit a nested event loop by enabling debuggee events. - */ - postNest: function DTA_postNest(aNestData) { - let windowUtils = this.browser - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.resumeTimeouts(); - windowUtils.suppressEventHandling(false); +DeviceTabActor.prototype.grip = function DTA_grip() { + dbg_assert(!this.exited, + 'grip() should not be called on exited browser actor.'); + dbg_assert(this.actorID, + 'tab should have an actorID.'); + return { + 'actor': this.actorID, + 'title': this.browser.title, + 'url': this.browser.document.documentURI } - }; /** - * The request types this actor can handle. + * Creates a thread actor and a pool for context-lifetime actors. It then sets + * up the content window for debugging. */ -DeviceTabActor.prototype.requestTypes = { - 'attach': DeviceTabActor.prototype.onAttach, - 'detach': DeviceTabActor.prototype.onDetach +DeviceTabActor.prototype._pushContext = function DTA_pushContext() { + dbg_assert(!this._contextPool, "Can't push multiple contexts"); + + this._contextPool = new ActorPool(this.conn); + this.conn.addActorPool(this._contextPool); + + this.threadActor = new ThreadActor(this); + this._addDebuggees(this.browser.wrappedJSObject); + this._contextPool.addActor(this.threadActor); +}; + +// Protocol Request Handlers + +/** + * Prepare to enter a nested event loop by disabling debuggee events. + */ +DeviceTabActor.prototype.preNest = function DTA_preNest() { + let windowUtils = this.browser + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.suppressEventHandling(true); + windowUtils.suspendTimeouts(); +}; + +/** + * Prepare to exit a nested event loop by enabling debuggee events. + */ +DeviceTabActor.prototype.postNest = function DTA_postNest(aNestData) { + let windowUtils = this.browser + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + windowUtils.resumeTimeouts(); + windowUtils.suppressEventHandling(false); }; diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index f79bfe82961..58450e21b5d 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -485,6 +485,7 @@ function startDebugger() { if (!DebuggerServer.initialized) { // Allow remote connections. DebuggerServer.init(function () { return true; }); + DebuggerServer.addBrowserActors(); DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js'); } diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5f9173031ee..923ed1b88d8 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -6098,6 +6098,7 @@ var RemoteDebugger = { try { if (!DebuggerServer.initialized) { DebuggerServer.init(this._allowConnection); + DebuggerServer.addBrowserActors(); DebuggerServer.addActors("chrome://browser/content/dbg-browser-actors.js"); } diff --git a/mobile/android/chrome/content/dbg-browser-actors.js b/mobile/android/chrome/content/dbg-browser-actors.js index f9a225a50e8..1e59280cfa2 100644 --- a/mobile/android/chrome/content/dbg-browser-actors.js +++ b/mobile/android/chrome/content/dbg-browser-actors.js @@ -5,14 +5,16 @@ "use strict"; /** - * Fennec-specific actors. + * Fennec-specific root actor that extends BrowserRootActor and overrides some + * of its methods. */ -var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"] - .getService(Ci.nsIWindowMediator); - +/** + * The function that creates the root actor. DebuggerServer expects to find this + * function in the loaded actors in order to initialize properly. + */ function createRootActor(aConnection) { - return new BrowserRootActor(aConnection); + return new FennecRootActor(aConnection); } /** @@ -24,412 +26,94 @@ function createRootActor(aConnection) { * @param aConnection DebuggerServerConnection * The conection to the client. */ -function BrowserRootActor(aConnection) { - this.conn = aConnection; - this._tabActors = new WeakMap(); - this._tabActorPool = null; - this._actorFactories = null; - - this.onTabClosed = this.onTabClosed.bind(this); - windowMediator.addListener(this); +function FennecRootActor(aConnection) { + BrowserRootActor.call(this, aConnection); } -BrowserRootActor.prototype = { - /** - * Return a 'hello' packet as specified by the Remote Debugging Protocol. - */ - sayHello: function BRA_sayHello() { - return { from: "root", - applicationType: "browser", - traits: [] }; - }, - - /** - * Disconnects the actor from the browser window. - */ - disconnect: function BRA_disconnect() { - windowMediator.removeListener(this); - - // We may have registered event listeners on browser windows to - // watch for tab closes, remove those. - let win = windowMediator.getMostRecentWindow("navigator:browser"); - this.unwatchWindow(win); - - // Signal our imminent shutdown. - let evt = win.document.createEvent("Event"); - evt.initEvent("Debugger:Shutdown", true, false); - win.document.documentElement.dispatchEvent(evt); - }, - - /** - * Handles the listTabs request. Builds a list of actors - * for the tabs running in the process. The actors will survive - * until at least the next listTabs request. - */ - onListTabs: function BRA_onListTabs() { - // Get actors for all the currently-running tabs (reusing - // existing actors where applicable), and store them in - // an ActorPool. - - let actorPool = new ActorPool(this.conn); - let actorList = []; - - let win = windowMediator.getMostRecentWindow("navigator:browser"); - this.browser = win.BrowserApp.selectedBrowser; - - // Watch the window for tab closes so we can invalidate - // actors as needed. - this.watchWindow(win); - - let tabs = win.BrowserApp.tabs; - let selected; - - for each (let tab in tabs) { - let browser = tab.browser; - - if (browser == this.browser) { - selected = actorList.length; - } - - let actor = this._tabActors.get(browser); - if (!actor) { - actor = new BrowserTabActor(this.conn, browser); - actor.parentID = this.actorID; - this._tabActors.set(browser, actor); - } - - actorPool.addActor(actor); - actorList.push(actor); - } - - // Now drop the old actorID -> actor map. Actors that still - // mattered were added to the new map, others will go - // away. - if (this._tabActorPool) { - this.conn.removeActorPool(this._tabActorPool); - } - - this._tabActorPool = actorPool; - this.conn.addActorPool(this._tabActorPool); - - return { "from": "root", - "selected": selected, - "tabs": [actor.grip() - for each (actor in actorList)] }; - }, - - /** - * Watch a window that was visited during onListTabs for - * tab closures. - */ - watchWindow: function BRA_watchWindow(aWindow) { - let tabContainer = aWindow.document.getElementById("browsers"); - tabContainer.addEventListener("TabClose", - this.onTabClosed, - false); - }, - - /** - * Stop watching a window for tab closes. - */ - unwatchWindow: function BRA_unwatchWindow(aWindow) { - let tabContainer = aWindow.document.getElementById("browsers"); - tabContainer.removeEventListener("TabClose", this.onTabClosed); - this.exitTabActor(aWindow); - }, - - /** - * When a tab is closed, exit its tab actor. The actor - * will be dropped at the next listTabs request. - */ - onTabClosed: function BRA_onTabClosed(aEvent) { - this.exitTabActor(aEvent.target.browser); - }, - - /** - * Exit the tab actor of the specified tab. - */ - exitTabActor: function BRA_exitTabActor(aWindow) { - let actor = this._tabActors.get(aWindow); - if (actor) { - actor.exit(); - } - }, - - // nsIWindowMediatorListener - onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { }, - onOpenWindow: function BRA_onOpenWindow(aWindow) { }, - onCloseWindow: function BRA_onCloseWindow(aWindow) { - if (aWindow.BrowserApp) { - this.unwatchWindow(aWindow); - } - } -} +FennecRootActor.prototype = new BrowserRootActor(); /** - * The request types this actor can handle. + * Handles the listTabs request. Builds a list of actors + * for the tabs running in the process. The actors will survive + * until at least the next listTabs request. */ -BrowserRootActor.prototype.requestTypes = { - "listTabs": BrowserRootActor.prototype.onListTabs +FennecRootActor.prototype.onListTabs = function FRA_onListTabs() { + // Get actors for all the currently-running tabs (reusing + // existing actors where applicable), and store them in + // an ActorPool. + + let actorPool = new ActorPool(this.conn); + let actorList = []; + + let win = windowMediator.getMostRecentWindow("navigator:browser"); + this.browser = win.BrowserApp.selectedBrowser; + + // Watch the window for tab closes so we can invalidate + // actors as needed. + this.watchWindow(win); + + let tabs = win.BrowserApp.tabs; + let selected; + + for each (let tab in tabs) { + let browser = tab.browser; + + if (browser == this.browser) { + selected = actorList.length; + } + + let actor = this._tabActors.get(browser); + if (!actor) { + actor = new BrowserTabActor(this.conn, browser); + actor.parentID = this.actorID; + this._tabActors.set(browser, actor); + } + + actorPool.addActor(actor); + actorList.push(actor); + } + + // Now drop the old actorID -> actor map. Actors that still + // mattered were added to the new map, others will go + // away. + if (this._tabActorPool) { + this.conn.removeActorPool(this._tabActorPool); + } + + this._tabActorPool = actorPool; + this.conn.addActorPool(this._tabActorPool); + + return { "from": "root", + "selected": selected, + "tabs": [actor.grip() + for each (actor in actorList)] }; }; /** - * Creates a tab actor for handling requests to a browser tab, like attaching - * and detaching. - * - * @param aConnection DebuggerServerConnection - * The conection to the client. - * @param aBrowser browser - * The browser instance that contains this tab. + * Return the tab container for the specified window. */ -function BrowserTabActor(aConnection, aBrowser) -{ - this.conn = aConnection; - this._browser = aBrowser; +FennecRootActor.prototype.getTabContainer = function FRA_getTabContainer(aWindow) { + return aWindow.document.getElementById("browsers"); +}; - this._onWindowCreated = this.onWindowCreated.bind(this); -} +/** + * When a tab is closed, exit its tab actor. The actor + * will be dropped at the next listTabs request. + */ +FennecRootActor.prototype.onTabClosed = function FRA_onTabClosed(aEvent) { + this.exitTabActor(aEvent.target.browser); +}; -// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a -// *complete* mess, needs to be rethought asap. - -BrowserTabActor.prototype = { - get browser() { return this._browser; }, - - get exited() { return !this._browser; }, - get attached() { return !!this._attached }, - - _tabPool: null, - get tabActorPool() { return this._tabPool; }, - - _contextPool: null, - get contextActorPool() { return this._contextPool; }, - - /** - * Add the specified breakpoint to the default actor pool connection, in order - * to be alive as long as the server is. - * - * @param BreakpointActor aActor - * The actor object. - */ - addToBreakpointPool: function BTA_addToBreakpointPool(aActor) { - this.conn.addActor(aActor); - }, - - /** - * Remove the specified breakpint from the default actor pool. - * - * @param string aActor - * The actor ID. - */ - removeFromBreakpointPool: function BTA_removeFromBreakpointPool(aActor) { - this.conn.removeActor(aActor); - }, - - actorPrefix: "tab", - - grip: function BTA_grip() { - dbg_assert(!this.exited, - "grip() shouldn't be called on exited browser actor."); - dbg_assert(this.actorID, - "tab should have an actorID."); - return { actor: this.actorID, - title: this._browser.contentTitle, - url: this._browser.currentURI.spec } - }, - - /** - * Called when the actor is removed from the connection. - */ - disconnect: function BTA_disconnect() { - this._detach(); - }, - - /** - * Called by the root actor when the underlying tab is closed. - */ - exit: function BTA_exit() { - if (this.exited) { - return; - } - - if (this.attached) { - this._detach(); - this.conn.send({ from: this.actorID, - type: "tabDetached" }); - } - - this._browser = null; - }, - - /** - * Does the actual work of attching to a tab. - */ - _attach: function BTA_attach() { - if (this._attached) { - return; - } - - // Create a pool for tab-lifetime actors. - dbg_assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached."); - this._tabPool = new ActorPool(this.conn); - this.conn.addActorPool(this._tabPool); - - // ... and a pool for context-lifetime actors. - this._pushContext(); - - // Watch for globals being created in this tab. - this._browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true); - - this._attached = true; - }, - - /** - * Creates a thread actor and a pool for context-lifetime actors. It then sets - * up the content window for debugging. - */ - _pushContext: function BTA_pushContext() { - dbg_assert(!this._contextPool, "Can't push multiple contexts"); - - this._contextPool = new ActorPool(this.conn); - this.conn.addActorPool(this._contextPool); - - this.threadActor = new ThreadActor(this); - this._addDebuggees(this._browser.contentWindow.wrappedJSObject); - this._contextPool.addActor(this.threadActor); - }, - - /** - * Add the provided window and all windows in its frame tree as debuggees. - */ - _addDebuggees: function BTA__addDebuggees(aWindow) { - this.threadActor.addDebuggee(aWindow); - let frames = aWindow.frames; - for (let i = 0; i < frames.length; i++) { - this._addDebuggees(frames[i]); - } - }, - - /** - * Exits the current thread actor and removes the context-lifetime actor pool. - * The content window is no longer being debugged after this call. - */ - _popContext: function BTA_popContext() { - dbg_assert(!!this._contextPool, "No context to pop."); - - this.conn.removeActorPool(this._contextPool); - this._contextPool = null; - this.threadActor.exit(); - this.threadActor = null; - }, - - /** - * Does the actual work of detaching from a tab. - */ - _detach: function BTA_detach() { - if (!this.attached) { - return; - } - - this._browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true); - - this._popContext(); - - // Shut down actors that belong to this tab's pool. - this.conn.removeActorPool(this._tabPool); - this._tabPool = null; - - this._attached = false; - }, - - // Protocol Request Handlers - - onAttach: function BTA_onAttach(aRequest) { - if (this.exited) { - return { type: "exited" }; - } - - this._attach(); - - return { type: "tabAttached", threadActor: this.threadActor.actorID }; - }, - - onDetach: function BTA_onDetach(aRequest) { - if (!this.attached) { - return { error: "wrongState" }; - } - - this._detach(); - - return { type: "detached" }; - }, - - /** - * Prepare to enter a nested event loop by disabling debuggee events. - */ - preNest: function BTA_preNest() { - if (!this._browser) { - // The tab is already closed. - return; - } - let windowUtils = this._browser.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.suppressEventHandling(true); - windowUtils.suspendTimeouts(); - }, - - /** - * Prepare to exit a nested event loop by enabling debuggee events. - */ - postNest: function BTA_postNest(aNestData) { - if (!this._browser) { - // The tab is already closed. - return; - } - let windowUtils = this._browser.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - windowUtils.resumeTimeouts(); - windowUtils.suppressEventHandling(false); - }, - - /** - * Handle location changes, by sending a tabNavigated notification to the - * client. - */ - onWindowCreated: function BTA_onWindowCreated(evt) { - if (evt.target === this._browser.contentDocument) { - if (this._attached) { - this.conn.send({ from: this.actorID, type: "tabNavigated", - url: this._browser.contentDocument.URL }); - } - } +// nsIWindowMediatorListener +FennecRootActor.prototype.onCloseWindow = function FRA_onCloseWindow(aWindow) { + if (aWindow.BrowserApp) { + this.unwatchWindow(aWindow); } }; /** * The request types this actor can handle. */ -BrowserTabActor.prototype.requestTypes = { - "attach": BrowserTabActor.prototype.onAttach, - "detach": BrowserTabActor.prototype.onDetach -}; - -/** - * Registers handlers for new request types defined dynamically. This is used - * for example by add-ons to augment the functionality of the tab actor. - * - * @param aName string - * The name of the new request type. - * @param aFunction function - * The handler for this request type. - */ -DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) { - BrowserTabActor.prototype.requestTypes[aName] = function(aRequest) { - if (!this.attached) { - return { error: "wrongState" }; - } - return aFunction(this, aRequest); - } +FennecRootActor.prototype.requestTypes = { + "listTabs": FennecRootActor.prototype.onListTabs }; diff --git a/toolkit/devtools/debugger/server/dbg-browser-actors.js b/toolkit/devtools/debugger/server/dbg-browser-actors.js index 58a919338fc..0e46ec8e424 100644 --- a/toolkit/devtools/debugger/server/dbg-browser-actors.js +++ b/toolkit/devtools/debugger/server/dbg-browser-actors.js @@ -128,20 +128,27 @@ BrowserRootActor.prototype = { * tab closures. */ watchWindow: function BRA_watchWindow(aWindow) { - aWindow.getBrowser().tabContainer.addEventListener("TabClose", - this.onTabClosed, - false); + this.getTabContainer(aWindow).addEventListener("TabClose", + this.onTabClosed, + false); }, /** * Stop watching a window for tab closes. */ unwatchWindow: function BRA_unwatchWindow(aWindow) { - aWindow.getBrowser().tabContainer.removeEventListener("TabClose", - this.onTabClosed); + this.getTabContainer(aWindow).removeEventListener("TabClose", + this.onTabClosed); this.exitTabActor(aWindow); }, + /** + * Return the tab container for the specified window. + */ + getTabContainer: function BRA_getTabContainer(aWindow) { + return aWindow.getBrowser().tabContainer; + }, + /** * When a tab is closed, exit its tab actor. The actor * will be dropped at the next listTabs request.