Bug 1550519 - Show a translucent parent highlight when a subgrid is highlighted....
[gecko.git] / remote / WindowManager.jsm
blob69720dc0707c4543807acdcd8e89dbb05b10d279
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 "use strict";
7 var EXPORTED_SYMBOLS = [
8   "TabManager",
9   "TabObserver",
10   "WindowObserver",
13 const {DOMContentLoadedPromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
14 const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
15 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
17 /**
18  * The WindowManager provides tooling for application-agnostic
19  * observation of windows, tabs, and content browsers as they are
20  * created and destroyed.
21  */
23 // TODO(ato):
25 // The DOM team is working on pulling browsing context related behaviour,
26 // such as window and tab handling, out of product code and into the platform.
27 // This will have implication for the remote agent,
28 // and as the platform gains support for product-independent events
29 // we can likely get rid of this entire module.
31 /**
32  * Observes DOMWindows as they open and close.
33  *
34  * "open" fires when a window opens.
35  * "close" fires when a window closes.
36  */
37 class WindowObserver {
38   /**
39    * @param {boolean?} [false] registerExisting
40    *     Events will be despatched for the ChromeWindows that exist
41    *     at the time the observer is started.
42    */
43   constructor({registerExisting = false} = {}) {
44     this.registerExisting = registerExisting;
45     EventEmitter.decorate(this);
46   }
48   async start() {
49     if (this.registerExisting) {
50       for (const window of Services.wm.getEnumerator("navigator:browser")) {
51         await this.onOpenWindow(window);
52       }
53     }
55     Services.wm.addListener(this);
56   }
58   stop() {
59     Services.wm.removeListener(this);
60   }
62   // nsIWindowMediatorListener
64   async onOpenWindow(xulWindow) {
65     const window = xulWindow
66         .QueryInterface(Ci.nsIInterfaceRequestor)
67         .getInterface(Ci.nsIDOMWindow);
68     await new DOMContentLoadedPromise(window);
69     this.emit("open", window);
70   }
72   onCloseWindow(xulWindow) {
73     const window = xulWindow
74         .QueryInterface(Ci.nsIInterfaceRequestor)
75         .getInterface(Ci.nsIDOMWindow);
76     this.emit("close", window);
77   }
79   // XPCOM
81   get QueryInterface() {
82     return ChromeUtils.generateQI([Ci.nsIWindowMediatorListener]);
83   }
86 /**
87  * Observe Firefox tabs as they open and close.
88  *
89  * "open" fires when a tab opens.
90  * "close" fires when a tab closes.
91  */
92 class TabObserver {
93   /**
94    * @param {boolean?} [false] registerExisting
95    *     Events will be fired for ChromeWIndows and their respective tabs
96    *     at the time when the observer is started.
97    */
98   constructor({registerExisting = false} = {}) {
99     this.windows = new WindowObserver({registerExisting});
100     EventEmitter.decorate(this);
101   }
103   async start() {
104     this.windows.on("open", this.onWindowOpen.bind(this));
105     this.windows.on("close", this.onWindowClose.bind(this));
106     await this.windows.start();
107   }
109   stop() {
110     this.windows.off("open");
111     this.windows.off("close");
112     this.windows.stop();
113   }
115   onTabOpen(tab) {
116     this.emit("open", tab);
117   }
119   onTabClose(tab) {
120     this.emit("close", tab);
121   }
123   // WindowObserver
125   async onWindowOpen(eventName, window) {
126     if (!window.gBrowser) {
127       return;
128     }
130     for (const tab of window.gBrowser.tabs) {
131       // a missing linkedBrowser means the tab is still initialising,
132       // and a TabOpen event will fire once it is ready
133       if (!tab.linkedBrowser) {
134         continue;
135       }
136       this.onTabOpen(tab);
137     }
139     window.addEventListener("TabOpen", ({target}) => this.onTabOpen(target));
140     window.addEventListener("TabClose", ({target}) => this.onTabClose(target));
141   }
143   onWindowClose(window) {
144     // TODO(ato): Is TabClose fired when the window closes?
145   }
148 var TabManager = {
149   addTab() {
150     const window = Services.wm.getMostRecentWindow("navigator:browser");
151     const { gBrowser } = window;
152     const tab = gBrowser.addTab("about:blank", {
153       triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
154     });
155     gBrowser.selectedTab = tab;
156     return tab;
157   },