Bug 1890689 Don't pretend to pre-buffer with DynamicResampler r=pehrsons
[gecko.git] / browser / modules / EveryWindow.sys.mjs
blob64e7cbaa31be611c2d2d8ffb40f77359dbb5156f
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/. */
5 /*
6  * This module enables consumers to register callbacks on every
7  * current and future browser window.
8  *
9  * Usage: EveryWindow.registerCallback(id, init, uninit);
10  *        EveryWindow.unregisterCallback(id);
11  *
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.
15  *
16  * Each callback will receive the window for which it is presently
17  * being called as the first argument.
18  *
19  * init is called on every existing window at the time of registration,
20  * and on all future windows at browser-delayed-startup-finished.
21  *
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`.
25  */
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(() => {
34       callback(win);
35     });
36   }
39 export const EveryWindow = {
40   /**
41    * The current list of all browser windows whose delayedStartupPromise has resolved
42    */
43   get readyWindows() {
44     return Array.from(Services.wm.getEnumerator("navigator:browser")).filter(
45       win => win.gBrowserInit?.delayedStartupFinished
46     );
47   },
49   /**
50    * Registers init and uninit functions to be called on every window.
51    *
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.
59    */
60   registerCallback: function EW_registerCallback(id, init, uninit) {
61     if (callbacks.has(id)) {
62       return false;
63     }
65     if (!initialized) {
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()) {
71               c.uninit(win, true);
72             }
73           }
74         }
75         Services.ww.registerNotification(observer);
76       };
78       Services.obs.addObserver(win => {
79         for (let c of callbacks.values()) {
80           c.init(win);
81         }
82         addUnloadListener(win);
83       }, "browser-delayed-startup-finished");
85       callForEveryWindow(addUnloadListener);
87       initialized = true;
88     }
90     callForEveryWindow(init);
91     callbacks.set(id, { id, init, uninit });
93     return true;
94   },
96   /**
97    * Unregisters a previously registered consumer.
98    *
99    * @param {string} id The id to unregister.
100    * @param {boolean} [callUninit=true] Whether to call the registered uninit
101    *   function on every window.
102    */
103   unregisterCallback: function EW_unregisterCallback(id, callUninit = true) {
104     if (!callbacks.has(id)) {
105       return;
106     }
108     if (callUninit) {
109       callForEveryWindow(callbacks.get(id).uninit);
110     }
112     callbacks.delete(id);
113   },