browser(firefox): reland "instrument all windows, support silent mode" with Linux fix (#1634)
This commit is contained in:
		
							parent
							
								
									c345cfee54
								
							
						
					
					
						commit
						e76f8de474
					
				|  | @ -1 +1 @@ | |||
| 1069 | ||||
| 1070 | ||||
|  |  | |||
|  | @ -2123,10 +2123,10 @@ index 0000000000000000000000000000000000000000..ba34976ad05e7f5f1a99777f76ac08b1 | |||
| +this.SimpleChannel = SimpleChannel;
 | ||||
| diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js
 | ||||
| new file mode 100644 | ||||
| index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff244ac0f6ac
 | ||||
| index 0000000000000000000000000000000000000000..9dd2c096cd9fa72ecda79a5ee56ef6176dc485d3
 | ||||
| --- /dev/null
 | ||||
| +++ b/juggler/TargetRegistry.js
 | ||||
| @@ -0,0 +1,492 @@
 | ||||
| @@ -0,0 +1,572 @@
 | ||||
| +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm');
 | ||||
| +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
 | ||||
| +const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js');
 | ||||
|  | @ -2138,6 +2138,7 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +const {NetworkHandler} = ChromeUtils.import("chrome://juggler/content/protocol/NetworkHandler.js");
 | ||||
| +const {RuntimeHandler} = ChromeUtils.import("chrome://juggler/content/protocol/RuntimeHandler.js");
 | ||||
| +const {AccessibilityHandler} = ChromeUtils.import("chrome://juggler/content/protocol/AccessibilityHandler.js");
 | ||||
| +const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 | ||||
| +
 | ||||
| +const Cc = Components.classes;
 | ||||
| +const Ci = Components.interfaces;
 | ||||
|  | @ -2154,7 +2155,7 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +];
 | ||||
| +
 | ||||
| +class TargetRegistry {
 | ||||
| +  constructor(mainWindow) {
 | ||||
| +  constructor() {
 | ||||
| +    EventEmitter.decorate(this);
 | ||||
| +
 | ||||
| +    this._browserContextIdToBrowserContext = new Map();
 | ||||
|  | @ -2170,22 +2171,20 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +
 | ||||
| +    this._defaultContext = new BrowserContext(this, undefined, undefined);
 | ||||
| +
 | ||||
| +    this._mainWindow = mainWindow;
 | ||||
| +    this._targets = new Map();
 | ||||
| +
 | ||||
| +    this._tabToTarget = new Map();
 | ||||
| +    Services.obs.addObserver(this, 'oop-frameloader-crashed');
 | ||||
| +
 | ||||
| +    for (const tab of this._mainWindow.gBrowser.tabs)
 | ||||
| +      this._createTargetForTab(tab);
 | ||||
| +    this._mainWindow.gBrowser.tabContainer.addEventListener('TabOpen', event => {
 | ||||
| +    const onTabOpenListener = event => {
 | ||||
| +      const target = this._createTargetForTab(event.target);
 | ||||
| +      // If we come here, content will have juggler script from the start,
 | ||||
| +      // and we should wait for initial navigation.
 | ||||
| +      target._waitForInitialNavigation = true;
 | ||||
| +      // For pages created before we attach to them, we don't wait for initial
 | ||||
| +      // navigation (target._waitForInitialNavigation is false by default).
 | ||||
| +    });
 | ||||
| +    this._mainWindow.gBrowser.tabContainer.addEventListener('TabClose', event => {
 | ||||
| +    };
 | ||||
| +
 | ||||
| +    const onTabCloseListener = event => {
 | ||||
| +      const tab = event.target;
 | ||||
| +      const target = this._tabToTarget.get(tab);
 | ||||
| +      if (!target)
 | ||||
|  | @ -2194,8 +2193,32 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +      this._tabToTarget.delete(tab);
 | ||||
| +      target.dispose();
 | ||||
| +      this.emit(TargetRegistry.Events.TargetDestroyed, target);
 | ||||
| +    });
 | ||||
| +    Services.obs.addObserver(this, 'oop-frameloader-crashed');
 | ||||
| +    };
 | ||||
| +
 | ||||
| +    const wmListener = {
 | ||||
| +      onOpenWindow: async window => {
 | ||||
| +        const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
 | ||||
| +        if (!(domWindow instanceof Ci.nsIDOMChromeWindow))
 | ||||
| +          return;
 | ||||
| +        await this._waitForWindowLoad(domWindow);
 | ||||
| +        for (const tab of domWindow.gBrowser.tabs)
 | ||||
| +          this._createTargetForTab(tab);
 | ||||
| +        domWindow.gBrowser.tabContainer.addEventListener('TabOpen', onTabOpenListener);
 | ||||
| +        domWindow.gBrowser.tabContainer.addEventListener('TabClose', onTabCloseListener);
 | ||||
| +      },
 | ||||
| +      onCloseWindow: window => {
 | ||||
| +        const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
 | ||||
| +        if (!(domWindow instanceof Ci.nsIDOMChromeWindow))
 | ||||
| +          return;
 | ||||
| +        if (!domWindow.gBrowser)
 | ||||
| +          return;
 | ||||
| +        domWindow.gBrowser.tabContainer.removeEventListener('TabOpen', onTabOpenListener);
 | ||||
| +        domWindow.gBrowser.tabContainer.removeEventListener('TabClose', onTabCloseListener);
 | ||||
| +        for (const tab of domWindow.gBrowser.tabs)
 | ||||
| +          onTabCloseListener({ target: tab });
 | ||||
| +      },
 | ||||
| +    };
 | ||||
| +    Services.wm.addListener(wmListener);
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  defaultContext() {
 | ||||
|  | @ -2210,13 +2233,42 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +    return this._browserContextIdToBrowserContext.get(browserContextId);
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  async _waitForWindowLoad(window) {
 | ||||
| +    if (window.document.readyState === 'complete')
 | ||||
| +      return;
 | ||||
| +    await new Promise(fulfill => {
 | ||||
| +      window.addEventListener('load', function listener() {
 | ||||
| +        window.removeEventListener('load', listener);
 | ||||
| +        fulfill();
 | ||||
| +      });
 | ||||
| +    });
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  async newPage({browserContextId}) {
 | ||||
| +    let window;
 | ||||
| +    let created = false;
 | ||||
| +    const windowsIt = Services.wm.getEnumerator('navigator:browser');
 | ||||
| +    if (windowsIt.hasMoreElements()) {
 | ||||
| +      window = windowsIt.getNext();
 | ||||
| +    } else {
 | ||||
| +      const features = "chrome,dialog=no,all";
 | ||||
| +      const args = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
 | ||||
| +      args.data = 'about:blank';
 | ||||
| +      window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args);
 | ||||
| +      created = true;
 | ||||
| +    }
 | ||||
| +    await this._waitForWindowLoad(window);
 | ||||
| +    const browserContext = this.browserContextForId(browserContextId);
 | ||||
| +    const tab = this._mainWindow.gBrowser.addTab('about:blank', {
 | ||||
| +    const tab = window.gBrowser.addTab('about:blank', {
 | ||||
| +      userContextId: browserContext.userContextId,
 | ||||
| +      triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
 | ||||
| +    });
 | ||||
| +    this._mainWindow.gBrowser.selectedTab = tab;
 | ||||
| +    if (created) {
 | ||||
| +      window.gBrowser.removeTab(window.gBrowser.getTabForBrowser(window.gBrowser.getBrowserAtIndex(0)), {
 | ||||
| +        skipPermitUnload: true,
 | ||||
| +      });
 | ||||
| +    }
 | ||||
| +    window.gBrowser.selectedTab = tab;
 | ||||
| +    const target = this._tabToTarget.get(tab);
 | ||||
| +    await target._contentReadyPromise;
 | ||||
| +    if (browserContext.options.timezoneId) {
 | ||||
|  | @ -2257,14 +2309,25 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +    return this._targets.get(targetId);
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  _tabForBrowser(browser) {
 | ||||
| +    // TODO: replace all of this with browser -> target map.
 | ||||
| +    const windowsIt = Services.wm.getEnumerator('navigator:browser');
 | ||||
| +    while (windowsIt.hasMoreElements()) {
 | ||||
| +      const window = windowsIt.getNext();
 | ||||
| +      const tab = window.gBrowser.getTabForBrowser(browser);
 | ||||
| +      if (tab)
 | ||||
| +        return { tab, gBrowser: window.gBrowser };
 | ||||
| +    }
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  _targetForBrowser(browser) {
 | ||||
| +    const tab = this._mainWindow.gBrowser.getTabForBrowser(browser);
 | ||||
| +    return tab ? this._tabToTarget.get(tab) : undefined;
 | ||||
| +    const tab = this._tabForBrowser(browser);
 | ||||
| +    return tab ? this._tabToTarget.get(tab.tab) : undefined;
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  browserContextForBrowser(browser) {
 | ||||
| +    const tab = this._mainWindow.gBrowser.getTabForBrowser(browser);
 | ||||
| +    return tab ? this._userContextIdToBrowserContext.get(tab.userContextId) : undefined;
 | ||||
| +    const tab = this._tabForBrowser(browser);
 | ||||
| +    return tab ? this._userContextIdToBrowserContext.get(tab.tab.userContextId) : undefined;
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  _createTargetForTab(tab) {
 | ||||
|  | @ -2287,6 +2350,10 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +      if (!target)
 | ||||
| +        return;
 | ||||
| +      target.emit('crashed');
 | ||||
| +      this._targets.delete(target.id());
 | ||||
| +      this._tabToTarget.delete(target._tab);
 | ||||
| +      target.dispose();
 | ||||
| +      this.emit(TargetRegistry.Events.TargetDestroyed, target);
 | ||||
| +      return;
 | ||||
| +    }
 | ||||
| +  }
 | ||||
|  | @ -2311,7 +2378,7 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +    this._eventListeners = [
 | ||||
| +      helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION),
 | ||||
| +      helper.addMessageListener(tab.linkedBrowser.messageManager, 'juggler:content-ready', {
 | ||||
| +        receiveMessage: () => this._onContentReady()
 | ||||
| +        receiveMessage: message => this._onContentReady(message.data)
 | ||||
| +      }),
 | ||||
| +    ];
 | ||||
| +
 | ||||
|  | @ -2357,7 +2424,8 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +  }
 | ||||
| +
 | ||||
| +  async close(runBeforeUnload = false) {
 | ||||
| +    await this._registry._mainWindow.gBrowser.removeTab(this._tab, {
 | ||||
| +    const tab = this._registry._tabForBrowser(this._tab.linkedBrowser);
 | ||||
| +    await tab.gBrowser.removeTab(this._tab, {
 | ||||
| +      skipPermitUnload: !runBeforeUnload,
 | ||||
| +    });
 | ||||
| +  }
 | ||||
|  | @ -2373,7 +2441,9 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +    networkHandler.enable();
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  _onContentReady() {
 | ||||
| +  _onContentReady({ userContextId }) {
 | ||||
| +    // TODO: this is the earliest when userContextId is available.
 | ||||
| +    // We should create target here, while listening to onContentReady for every tab.
 | ||||
| +    const sessions = [];
 | ||||
| +    const data = { sessions, target: this };
 | ||||
| +    this._registry.emit(TargetRegistry.Events.PageTargetReady, data);
 | ||||
|  | @ -2469,10 +2539,20 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +    }
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  destroy() {
 | ||||
| +  async destroy() {
 | ||||
| +    if (this.userContextId !== 0) {
 | ||||
| +      ContextualIdentityService.remove(this.userContextId);
 | ||||
| +      ContextualIdentityService.closeContainerTabs(this.userContextId);
 | ||||
| +      if (this.pages.size) {
 | ||||
| +        await new Promise(f => {
 | ||||
| +          const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => {
 | ||||
| +            if (!this.pages.size) {
 | ||||
| +              helper.removeListeners([listener]);
 | ||||
| +              f();
 | ||||
| +            }
 | ||||
| +          });
 | ||||
| +        });
 | ||||
| +      }
 | ||||
| +    }
 | ||||
| +    this._registry._browserContextIdToBrowserContext.delete(this.browserContextId);
 | ||||
| +    this._registry._userContextIdToBrowserContext.delete(this.userContextId);
 | ||||
|  | @ -2621,10 +2701,10 @@ index 0000000000000000000000000000000000000000..b74ea28f1ee7bbfeb6ea3fa9c5a4ff24 | |||
| +this.TargetRegistry = TargetRegistry;
 | ||||
| diff --git a/juggler/components/juggler.js b/juggler/components/juggler.js
 | ||||
| new file mode 100644 | ||||
| index 0000000000000000000000000000000000000000..50617b19845d32006873c15b446afc04651cb6b7
 | ||||
| index 0000000000000000000000000000000000000000..3477b09f25c90f2b5492d0dd9eb16d7496ec6480
 | ||||
| --- /dev/null
 | ||||
| +++ b/juggler/components/juggler.js
 | ||||
| @@ -0,0 +1,117 @@
 | ||||
| @@ -0,0 +1,85 @@
 | ||||
| +const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 | ||||
| +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 | ||||
| +const {Dispatcher} = ChromeUtils.import("chrome://juggler/content/protocol/Dispatcher.js");
 | ||||
|  | @ -2641,7 +2721,6 @@ index 0000000000000000000000000000000000000000..50617b19845d32006873c15b446afc04 | |||
| +
 | ||||
| +// Command Line Handler
 | ||||
| +function CommandLineHandler() {
 | ||||
| +  this._port = -1;
 | ||||
| +};
 | ||||
| +
 | ||||
| +CommandLineHandler.prototype = {
 | ||||
|  | @ -2658,31 +2737,39 @@ index 0000000000000000000000000000000000000000..50617b19845d32006873c15b446afc04 | |||
| +    const jugglerFlag = cmdLine.handleFlagWithParam("juggler", false);
 | ||||
| +    if (!jugglerFlag || isNaN(jugglerFlag))
 | ||||
| +      return;
 | ||||
| +    this._port = parseInt(jugglerFlag, 10);
 | ||||
| +    Services.obs.addObserver(this, 'sessionstore-windows-restored');
 | ||||
| +  },
 | ||||
| +    const port = parseInt(jugglerFlag, 10);
 | ||||
| +    const silent = cmdLine.preventDefault;
 | ||||
| +    if (silent)
 | ||||
| +      Services.startup.enterLastWindowClosingSurvivalArea();
 | ||||
| +
 | ||||
| +  observe: async function(subject, topic) {
 | ||||
| +    Services.obs.removeObserver(this, 'sessionstore-windows-restored');
 | ||||
| +
 | ||||
| +    const win = await waitForBrowserWindow();
 | ||||
| +    const targetRegistry = new TargetRegistry(win);
 | ||||
| +    const targetRegistry = new TargetRegistry();
 | ||||
| +    new NetworkObserver(targetRegistry);
 | ||||
| +
 | ||||
| +    const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
 | ||||
| +    const WebSocketServer = require('devtools/server/socket/websocket-server');
 | ||||
| +    this._server = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
 | ||||
| +    this._server.initSpecialConnection(this._port, Ci.nsIServerSocket.KeepWhenOffline | Ci.nsIServerSocket.LoopbackOnly, 4);
 | ||||
| +    this._server.initSpecialConnection(port, Ci.nsIServerSocket.KeepWhenOffline | Ci.nsIServerSocket.LoopbackOnly, 4);
 | ||||
| +
 | ||||
| +    const token = helper.generateId();
 | ||||
| +
 | ||||
| +    let windowsRestoredCallback;
 | ||||
| +    const windowsRestored = new Promise(fulfill => windowsRestoredCallback = fulfill);
 | ||||
| +    const removeObserver = helper.addObserver(() => {
 | ||||
| +      windowsRestoredCallback();
 | ||||
| +      removeObserver();
 | ||||
| +    }, "sessionstore-windows-restored");
 | ||||
| +
 | ||||
| +    this._server.asyncListen({
 | ||||
| +      onSocketAccepted: async(socket, transport) => {
 | ||||
| +        await windowsRestored;
 | ||||
| +        const input = transport.openInputStream(0, 0, 0);
 | ||||
| +        const output = transport.openOutputStream(0, 0, 0);
 | ||||
| +        const webSocket = await WebSocketServer.accept(transport, input, output, "/" + token);
 | ||||
| +        const dispatcher = new Dispatcher(webSocket);
 | ||||
| +        const browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry);
 | ||||
| +        const browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => {
 | ||||
| +          if (silent)
 | ||||
| +            Services.startup.exitLastWindowClosingSurvivalArea();
 | ||||
| +        });
 | ||||
| +        dispatcher.rootSession().registerHandler('Browser', browserHandler);
 | ||||
| +      }
 | ||||
| +    });
 | ||||
|  | @ -2703,45 +2790,6 @@ index 0000000000000000000000000000000000000000..50617b19845d32006873c15b446afc04 | |||
| +};
 | ||||
| +
 | ||||
| +var NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandLineHandler]);
 | ||||
| +
 | ||||
| +/**
 | ||||
| + * @return {!Promise<Ci.nsIDOMChromeWindow>}
 | ||||
| + */
 | ||||
| +async function waitForBrowserWindow() {
 | ||||
| +  const windowsIt = Services.wm.getEnumerator('navigator:browser');
 | ||||
| +  if (windowsIt.hasMoreElements())
 | ||||
| +    return waitForWindowLoaded(windowsIt.getNext());
 | ||||
| +
 | ||||
| +  let fulfill;
 | ||||
| +  let promise = new Promise(x => fulfill = x);
 | ||||
| +
 | ||||
| +  const listener = {
 | ||||
| +    onOpenWindow: window => {
 | ||||
| +      if (window instanceof Ci.nsIDOMChromeWindow) {
 | ||||
| +        Services.wm.removeListener(listener);
 | ||||
| +        fulfill(waitForWindowLoaded(window));
 | ||||
| +      }
 | ||||
| +    },
 | ||||
| +    onCloseWindow: () => {}
 | ||||
| +  };
 | ||||
| +  Services.wm.addListener(listener);
 | ||||
| +  return promise;
 | ||||
| +
 | ||||
| +  /**
 | ||||
| +   * @param {!Ci.nsIDOMChromeWindow} window
 | ||||
| +   * @return {!Promise<Ci.nsIDOMChromeWindow>}
 | ||||
| +   */
 | ||||
| +  function waitForWindowLoaded(window) {
 | ||||
| +    if (window.document.readyState === 'complete')
 | ||||
| +      return window;
 | ||||
| +    return new Promise(fulfill => {
 | ||||
| +      window.addEventListener('load', function listener() {
 | ||||
| +        window.removeEventListener('load', listener);
 | ||||
| +        fulfill(window);
 | ||||
| +      });
 | ||||
| +    });
 | ||||
| +  }
 | ||||
| +}
 | ||||
| diff --git a/juggler/components/juggler.manifest b/juggler/components/juggler.manifest
 | ||||
| new file mode 100644 | ||||
| index 0000000000000000000000000000000000000000..50f8930207563e0d6b8a7878fc602dbca54d77fc
 | ||||
|  | @ -5031,10 +5079,10 @@ index 0000000000000000000000000000000000000000..3a386425d3796d0a6786dea193b3402d | |||
| +
 | ||||
| diff --git a/juggler/content/main.js b/juggler/content/main.js
 | ||||
| new file mode 100644 | ||||
| index 0000000000000000000000000000000000000000..1864328a47107621309c9b3726bb84535b780c2f
 | ||||
| index 0000000000000000000000000000000000000000..e2a8fc14afe9b851e2bf3893691ca98c69bd12ee
 | ||||
| --- /dev/null
 | ||||
| +++ b/juggler/content/main.js
 | ||||
| @@ -0,0 +1,153 @@
 | ||||
| @@ -0,0 +1,156 @@
 | ||||
| +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 | ||||
| +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js');
 | ||||
| +const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js');
 | ||||
|  | @ -5094,7 +5142,10 @@ index 0000000000000000000000000000000000000000..1864328a47107621309c9b3726bb8453 | |||
| +}
 | ||||
| +
 | ||||
| +function initialize() {
 | ||||
| +  let response = sendSyncMessage('juggler:content-ready', {})[0];
 | ||||
| +  const loadContext = docShell.QueryInterface(Ci.nsILoadContext);
 | ||||
| +  const userContextId = loadContext.originAttributes.userContextId;
 | ||||
| +
 | ||||
| +  let response = sendSyncMessage('juggler:content-ready', { userContextId })[0];
 | ||||
| +  if (!response)
 | ||||
| +    response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false };
 | ||||
| +
 | ||||
|  | @ -5267,10 +5318,10 @@ index 0000000000000000000000000000000000000000..bf37558bccc48f4d90eadc971c1eb3e4 | |||
| +this.AccessibilityHandler = AccessibilityHandler;
 | ||||
| diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js
 | ||||
| new file mode 100644 | ||||
| index 0000000000000000000000000000000000000000..f63ee04a355e7426e13bd7095365bf44bb44648d
 | ||||
| index 0000000000000000000000000000000000000000..b4f0e856efb2331525c54c4d5ff124d83ea71ee6
 | ||||
| --- /dev/null
 | ||||
| +++ b/juggler/protocol/BrowserHandler.js
 | ||||
| @@ -0,0 +1,183 @@
 | ||||
| @@ -0,0 +1,185 @@
 | ||||
| +"use strict";
 | ||||
| +
 | ||||
| +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 | ||||
|  | @ -5280,7 +5331,7 @@ index 0000000000000000000000000000000000000000..f63ee04a355e7426e13bd7095365bf44 | |||
| +const helper = new Helper();
 | ||||
| +
 | ||||
| +class BrowserHandler {
 | ||||
| +  constructor(session, dispatcher, targetRegistry) {
 | ||||
| +  constructor(session, dispatcher, targetRegistry, onclose) {
 | ||||
| +    this._session = session;
 | ||||
| +    this._dispatcher = dispatcher;
 | ||||
| +    this._targetRegistry = targetRegistry;
 | ||||
|  | @ -5289,6 +5340,7 @@ index 0000000000000000000000000000000000000000..f63ee04a355e7426e13bd7095365bf44 | |||
| +    this._eventListeners = [];
 | ||||
| +    this._createdBrowserContextIds = new Set();
 | ||||
| +    this._attachedSessions = new Map();
 | ||||
| +    this._onclose = onclose;
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  async enable({attachToDefaultContext}) {
 | ||||
|  | @ -5326,8 +5378,8 @@ index 0000000000000000000000000000000000000000..f63ee04a355e7426e13bd7095365bf44 | |||
| +  async removeBrowserContext({browserContextId}) {
 | ||||
| +    if (!this._enabled)
 | ||||
| +      throw new Error('Browser domain is not enabled');
 | ||||
| +    await this._targetRegistry.browserContextForId(browserContextId).destroy();
 | ||||
| +    this._createdBrowserContextIds.delete(browserContextId);
 | ||||
| +    this._targetRegistry.browserContextForId(browserContextId).destroy();
 | ||||
| +  }
 | ||||
| +
 | ||||
| +  dispose() {
 | ||||
|  | @ -5383,6 +5435,7 @@ index 0000000000000000000000000000000000000000..f63ee04a355e7426e13bd7095365bf44 | |||
| +  }
 | ||||
| +
 | ||||
| +  async close() {
 | ||||
| +    this._onclose();
 | ||||
| +    let browserWindow = Services.wm.getMostRecentWindow(
 | ||||
| +      "navigator:browser"
 | ||||
| +    );
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue