1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This module enables consumers to register callbacks on every
7 * current and future browser window.
9 * Usage: EveryWindow.registerCallback(id, init, uninit);
10 * EveryWindow.unregisterCallback(id);
12 * id is expected to be a unique value that identifies the
13 * consumer, to be used for unregistration. If the id is already
14 * in use, registerCallback returns false without doing anything.
16 * Each callback will receive the window for which it is presently
17 * being called as the first argument.
19 * init is called on every existing window at the time of registration,
20 * and on all future windows at browser-delayed-startup-finished.
22 * uninit is called on every existing window if requested at the time
23 * of unregistration, and at the time of domwindowclosed.
24 * If the window is closing, a second argument is passed with value `true`.
27 var initialized = false;
28 var callbacks = new Map();
30 function callForEveryWindow(callback) {
31 let windowList = Services.wm.getEnumerator("navigator:browser");
32 for (let win of windowList) {
33 win.delayedStartupPromise.then(() => {
39 export const EveryWindow = {
41 * The current list of all browser windows whose delayedStartupPromise has resolved
44 return Array.from(Services.wm.getEnumerator("navigator:browser")).filter(
45 win => win.gBrowserInit?.delayedStartupFinished
50 * Registers init and uninit functions to be called on every window.
52 * @param {string} id A unique identifier for the consumer, to be
53 * used for unregistration.
54 * @param {function} init The function to be called on every currently
55 * existing window and every future window after delayed startup.
56 * @param {function} uninit The function to be called on every window
57 * at the time of callback unregistration or after domwindowclosed.
58 * @returns {boolean} Returns false if the id was taken, else true.
60 registerCallback: function EW_registerCallback(id, init, uninit) {
61 if (callbacks.has(id)) {
66 let addUnloadListener = win => {
67 function observer(subject, topic) {
68 if (topic == "domwindowclosed" && subject === win) {
69 Services.ww.unregisterNotification(observer);
70 for (let c of callbacks.values()) {
75 Services.ww.registerNotification(observer);
78 Services.obs.addObserver(win => {
79 for (let c of callbacks.values()) {
82 addUnloadListener(win);
83 }, "browser-delayed-startup-finished");
85 callForEveryWindow(addUnloadListener);
90 callForEveryWindow(init);
91 callbacks.set(id, { id, init, uninit });
97 * Unregisters a previously registered consumer.
99 * @param {string} id The id to unregister.
100 * @param {boolean} [callUninit=true] Whether to call the registered uninit
101 * function on every window.
103 unregisterCallback: function EW_unregisterCallback(id, callUninit = true) {
104 if (!callbacks.has(id)) {
109 callForEveryWindow(callbacks.get(id).uninit);
112 callbacks.delete(id);