Bug 1477506 - In overlay loader, add window creation listener before enumerating existing windows; r=Fallen a=jorgk
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 25 Jul 2019 16:37:38 +1200
changeset 36129 cfe5da4d82fe0fe9aff0e4cf551f891d46d331ae
parent 36128 1a066ca3911a23272f01e9c1e9ffd548f934d1c0
child 36130 71349d370678bb201e7566a6e83950ac58385496
push id392
push userclokep@gmail.com
push dateMon, 02 Sep 2019 20:17:19 +0000
reviewersFallen, jorgk
bugs1477506
Bug 1477506 - In overlay loader, add window creation listener before enumerating existing windows; r=Fallen a=jorgk
mail/components/extensions/parent/ext-legacy.js
--- a/mail/components/extensions/parent/ext-legacy.js
+++ b/mail/components/extensions/parent/ext-legacy.js
@@ -156,36 +156,42 @@ this.legacy = class extends ExtensionAPI
         }
 
         instance.observe(null, "profile-after-change", null);
       } catch (e) {
         console.error("Error firing profile-after-change listener for", contractid);
       }
     }
 
-    // Add overlays to all existing windows.
-    let enumerator = Services.wm.getEnumerator("mail:3pane");
-    if (enumerator.hasMoreElements() && enumerator.getNext().document.readyState == "complete") {
-      getAllWindows().forEach(w => {
-        if (["interactive", "complete"].includes(w.document.readyState)) {
-          Overlays.load(chromeManifest, w);
-        }
-      });
-    }
+    // Overlays.load must only be called once per window per extension.
+    // We use this WeakSet to remember all windows we've already seen.
+    let seenWindows = new WeakSet();
 
     // Listen for new windows to overlay.
     let documentObserver = {
-      observe(document) {
-        if (ExtensionCommon.instanceOf(document, "XULDocument")) {
-          Overlays.load(chromeManifest, document.defaultView);
+      observe(doc) {
+        let win = doc.defaultView;
+        if (ExtensionCommon.instanceOf(doc, "XULDocument") &&
+            !seenWindows.has(win)) {
+          seenWindows.add(win);
+          Overlays.load(chromeManifest, win);
         }
       },
     };
     Services.obs.addObserver(documentObserver, "chrome-document-interactive");
 
+    // Add overlays to all existing windows.
+    getAllWindows().forEach(win => {
+      if (["interactive", "complete"].includes(win.document.readyState) &&
+          !seenWindows.has(win)) {
+        seenWindows.add(win);
+        Overlays.load(chromeManifest, win);
+      }
+    });
+
     this.extension.callOnClose({
       close: () => {
         Services.obs.removeObserver(documentObserver, "chrome-document-interactive");
       },
     });
   }
 
   // The following functions are for bootstrapped add-ons.