diff options
Diffstat (limited to 'tools/addon-sdk-1.12/lib/sdk/windows/firefox.js')
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/windows/firefox.js | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/tools/addon-sdk-1.12/lib/sdk/windows/firefox.js b/tools/addon-sdk-1.12/lib/sdk/windows/firefox.js new file mode 100644 index 0000000..9a55a08 --- /dev/null +++ b/tools/addon-sdk-1.12/lib/sdk/windows/firefox.js @@ -0,0 +1,241 @@ +/* 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 { Cc, Ci, Cr } = require('chrome'), + { Trait } = require('../deprecated/traits'), + { List } = require('../deprecated/list'), + { EventEmitter } = require('../deprecated/events'), + { WindowTabs, WindowTabTracker } = require('./tabs-firefox'), + { WindowDom } = require('./dom'), + { WindowLoader } = require('./loader'), + { isBrowser, getWindowDocShell } = require('../window/utils'), + { Options } = require('../tabs/common'), + apiUtils = require('../deprecated/api-utils'), + unload = require('../system/unload'), + windowUtils = require('../deprecated/window-utils'), + { WindowTrackerTrait } = windowUtils, + { ns } = require('../core/namespace'), + { observer: windowObserver } = require('./observer'), + { isWindowPBEnabled } = require('../private-browsing/utils'); + +/** + * Window trait composes safe wrappers for browser window that are E10S + * compatible. + */ +const BrowserWindowTrait = Trait.compose( + EventEmitter, + WindowDom.resolve({ close: '_close' }), + WindowTabs, + WindowTabTracker, + WindowLoader, + /* WindowSidebars, */ + Trait.compose({ + _emit: Trait.required, + _close: Trait.required, + _load: Trait.required, + /** + * Constructor returns wrapper of the specified chrome window. + * @param {nsIWindow} window + */ + constructor: function BrowserWindow(options) { + // Register this window ASAP, in order to avoid loop that would try + // to create this window instance over and over (see bug 648244) + windows.push(this); + + // make sure we don't have unhandled errors + this.on('error', console.exception.bind(console)); + + if ('onOpen' in options) + this.on('open', options.onOpen); + if ('onClose' in options) + this.on('close', options.onClose); + if ('onActivate' in options) + this.on('activate', options.onActivate); + if ('onDeactivate' in options) + this.on('deactivate', options.onDeactivate); + if ('window' in options) + this._window = options.window; + + if ('tabs' in options) { + this._tabOptions = Array.isArray(options.tabs) ? + options.tabs.map(Options) : + [ Options(options.tabs) ]; + } + else if ('url' in options) { + this._tabOptions = [ Options(options.url) ]; + } + + this._load(); + return this; + }, + destroy: function () this._onUnload(), + _tabOptions: [], + _onLoad: function() { + try { + this._initWindowTabTracker(); + } + catch(e) { + this._emit('error', e); + } + + this._emitOnObject(browserWindows, 'open', this._public); + }, + _onUnload: function() { + if (!this._window) + return; + this._destroyWindowTabTracker(); + this._emitOnObject(browserWindows, 'close', this._public); + this._window = null; + // Removing reference from the windows array. + windows.splice(windows.indexOf(this), 1); + this._removeAllListeners(); + }, + close: function close(callback) { + // maybe we should deprecate this with message ? + if (callback) this.on('close', callback); + return this._close(); + } + }) +); + +/** + * Gets a `BrowserWindowTrait` for the given `chromeWindow` if previously + * registered, `null` otherwise. + */ +function getRegisteredWindow(chromeWindow) { + for each (let window in windows) { + if (chromeWindow === window._window) + return window; + } + + return null; +} + +/** + * Wrapper for `BrowserWindowTrait`. Creates new instance if wrapper for + * window doesn't exists yet. If wrapper already exists then returns it + * instead. + * @params {Object} options + * Options that are passed to the the `BrowserWindowTrait` + * @returns {BrowserWindow} + * @see BrowserWindowTrait + */ +function BrowserWindow(options) { + let window = null; + + if ("window" in options) + window = getRegisteredWindow(options.window); + + return (window || BrowserWindowTrait(options))._public; +} +// to have proper `instanceof` behavior will go away when #596248 is fixed. +BrowserWindow.prototype = BrowserWindowTrait.prototype; +exports.BrowserWindow = BrowserWindow; + +const windows = []; + +const browser = ns(); + +function onWindowActivation (chromeWindow, event) { + if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window. + + let window = getRegisteredWindow(chromeWindow); + + if (window) + window._emit(event.type, window._public); + else + window = BrowserWindowTrait({ window: chromeWindow }); + + browser(browserWindows).internals._emit(event.type, window._public); +} + +windowObserver.on("activate", onWindowActivation); +windowObserver.on("deactivate", onWindowActivation); + +/** + * `BrowserWindows` trait is composed out of `List` trait and it represents + * "live" list of currently open browser windows. Instance mutates itself + * whenever new browser window gets opened / closed. + */ +// Very stupid to resolve all `toStrings` but this will be fixed by #596248 +const browserWindows = Trait.resolve({ toString: null }).compose( + List.resolve({ constructor: '_initList' }), + EventEmitter.resolve({ toString: null }), + WindowTrackerTrait.resolve({ constructor: '_initTracker', toString: null }), + Trait.compose({ + _emit: Trait.required, + _add: Trait.required, + _remove: Trait.required, + + // public API + + /** + * Constructor creates instance of `Windows` that represents live list of open + * windows. + */ + constructor: function BrowserWindows() { + browser(this._public).internals = this; + + this._trackedWindows = []; + this._initList(); + this._initTracker(); + unload.ensure(this, "_destructor"); + }, + _destructor: function _destructor() { + this._removeAllListeners('open'); + this._removeAllListeners('close'); + this._removeAllListeners('activate'); + this._removeAllListeners('deactivate'); + this._clear(); + + delete browser(this._public).internals; + }, + /** + * This property represents currently active window. + * Property is non-enumerable, in order to preserve array like enumeration. + * @type {Window|null} + */ + get activeWindow() { + let window = windowUtils.activeBrowserWindow; + return window ? BrowserWindow({window: window}) : null; + }, + open: function open(options) { + if (typeof options === "string") + // `tabs` option is under review and may be removed. + options = { tabs: [Options(options)] }; + return BrowserWindow(options); + }, + + /** + * Internal listener which is called whenever new window gets open. + * Creates wrapper and adds to this list. + * @param {nsIWindow} chromeWindow + */ + _onTrack: function _onTrack(chromeWindow) { + if (!isBrowser(chromeWindow)) return; + let window = BrowserWindow({ window: chromeWindow }); + this._add(window); + this._emit('open', window); + }, + /** + * Internal listener which is called whenever window gets closed. + * Cleans up references and removes wrapper from this list. + * @param {nsIWindow} window + */ + _onUntrack: function _onUntrack(chromeWindow) { + if (!isBrowser(chromeWindow)) return; + let window = BrowserWindow({ window: chromeWindow }); + this._remove(window); + this._emit('close', window); + + // Bug 724404: do not leak this module and linked windows: + // We have to do it on untrack and not only when `_onUnload` is called + // when windows are closed, otherwise, we will leak on addon disabling. + window.destroy(); + } + }).resolve({ toString: null }) +)(); + +exports.browserWindows = browserWindows; |