Bug 1415913 - tabs.create without a windowId should target only normal windows, r=aswan
authorBob Silverberg <bsilverberg@mozilla.com>
Mon, 20 Nov 2017 17:00:20 -0500
changeset 394232 100e07f0bd493323d3b2e63686f0342a3f9a840b
parent 394231 2af8e91e49fd81fc80a158e5e34b60824fe7443b
child 394233 18717bbecba151490eb73a2183f81e1801d50fbe
push id56245
push userbsilverberg@mozilla.com
push dateWed, 29 Nov 2017 18:23:04 +0000
treeherderautoland@100e07f0bd49 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1415913, 1421709
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1415913 - tabs.create without a windowId should target only normal windows, r=aswan This introduces a new property to WindowTracker (on desktop only) called topNormalWindow which returns the topmost window which is not a popup window. That property is then used by tabs.create to identify the top "normal" window when a windowId is not passed to it. Bug 1421709 has been filed to look for other opportunities to use topNormalWindow in place of topWindow in our codebase. MozReview-Commit-ID: DcV93wO6FoV
browser/components/extensions/ext-browser.js
browser/components/extensions/ext-tabs.js
browser/components/extensions/test/browser/browser_ext_tabs_create.js
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -9,16 +9,18 @@
 /* global EventEmitter:false, TabContext:false, WindowEventManager:false,
           makeWidgetId:false, tabTracker:true, windowTracker:true */
 /* import-globals-from ../../../toolkit/components/extensions/ext-toolkit.js */
 
 /* globals TabBase, WindowBase, TabTrackerBase, WindowTrackerBase, TabManagerBase, WindowManagerBase */
 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+                                  "resource:///modules/RecentWindow.jsm");
 
 var {
   ExtensionError,
   defineLazyGetter,
 } = ExtensionUtils;
 
 const READER_MODE_PREFIX = "about:reader";
 
@@ -168,16 +170,27 @@ global.TabContext = class extends EventE
 class WindowTracker extends WindowTrackerBase {
   addProgressListener(window, listener) {
     window.gBrowser.addTabsProgressListener(listener);
   }
 
   removeProgressListener(window, listener) {
     window.gBrowser.removeTabsProgressListener(listener);
   }
+
+  /**
+   * @property {DOMWindow|null} topNormalWindow
+   *        The currently active, or topmost, browser window, or null if no
+   *        browser window is currently open.
+   *        Will return the topmost "normal" (i.e., not popup) window.
+   *        @readonly
+   */
+  get topNormalWindow() {
+    return RecentWindow.getMostRecentBrowserWindow({allowPopups: false});
+  }
 }
 
 /**
  * An event manager API provider which listens for a DOM event in any browser
  * window, and calls the given listener function whenever an event is received.
  * That listener function receives a `fire` object, which it can use to dispatch
  * events to the extension, and a DOM event object.
  *
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -323,17 +323,17 @@ this.tabs = class extends ExtensionAPI {
             tabTracker.off("tab-isarticle", isArticleChangeListener);
           };
         }).api(),
 
         create(createProperties) {
           return new Promise((resolve, reject) => {
             let window = createProperties.windowId !== null ?
               windowTracker.getWindow(createProperties.windowId, context) :
-              windowTracker.topWindow;
+              windowTracker.topNormalWindow;
 
             if (!window.gBrowser) {
               let obs = (finishedWindow, topic, data) => {
                 if (finishedWindow != window) {
                   return;
                 }
                 Services.obs.removeObserver(obs, "browser-delayed-startup-finished");
                 resolve(window);
--- a/browser/components/extensions/test/browser/browser_ext_tabs_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_create.js
@@ -220,8 +220,32 @@ add_task(async function test_urlbar_focu
   is(active.tagName, "html:input", "Input element focused");
   ok(active.classList.contains("urlbar-input"), "Urlbar focused");
 
   extension.sendMessage("remove", tab2.id);
   await extension.awaitMessage("result");
 
   await extension.unload();
 });
+
+add_task(async function test_create_with_popup() {
+  const extension = ExtensionTestUtils.loadExtension({
+    async background() {
+      let normalWin = await browser.windows.create();
+      let lastFocusedNormalWin = await browser.windows.getLastFocused({});
+      browser.test.assertEq(lastFocusedNormalWin.id, normalWin.id, "The normal window is the last focused window.");
+      let popupWin = await browser.windows.create({type: "popup"});
+      let lastFocusedPopupWin = await browser.windows.getLastFocused({});
+      browser.test.assertEq(lastFocusedPopupWin.id, popupWin.id, "The popup window is the last focused window.");
+      let newtab = await browser.tabs.create({});
+      browser.test.assertEq(normalWin.id, newtab.windowId, "New tab was created in last focused normal window.");
+      await Promise.all([
+        browser.windows.remove(normalWin.id),
+        browser.windows.remove(popupWin.id),
+      ]);
+      browser.test.sendMessage("complete");
+    },
+  });
+
+  await extension.startup();
+  await extension.awaitMessage("complete");
+  await extension.unload();
+});