Bug 1253128: [webext] Support type=popup in the browser.windows API. r=billm
authorKris Maglione <maglione.k@gmail.com>
Thu, 03 Mar 2016 18:44:18 -0800
changeset 325180 b29add2c129122e4af8582cac68259c0cc96baec
parent 325179 2e3b78d27f7b0d036d29435d7bb2241947823bb5
child 325181 46210f3ae07855edfe1383210d78433e38a6b564
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1253128
milestone47.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 1253128: [webext] Support type=popup in the browser.windows API. r=billm MozReview-Commit-ID: ALgprY2w7w9
browser/components/extensions/ext-utils.js
browser/components/extensions/ext-windows.js
browser/components/extensions/schemas/windows.json
browser/components/extensions/test/browser/browser_ext_windows_create.js
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -620,16 +620,26 @@ global.WindowManager = {
   WINDOW_ID_CURRENT: -2,
 
   get topWindow() {
     return Services.wm.getMostRecentWindow("navigator:browser");
   },
 
   windowType(window) {
     // TODO: Make this work.
+
+    let {chromeFlags} = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDocShell)
+                              .treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIXULWindow);
+
+    if (chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) {
+      return "popup";
+    }
+
     return "normal";
   },
 
   getId(window) {
     if (this._windows.has(window)) {
       return this._windows.get(window);
     }
     let id = this._nextId++;
@@ -703,18 +713,16 @@ global.WindowManager = {
     let result = {
       id: this.getId(window),
       focused: window.document.hasFocus(),
       top: window.screenY,
       left: window.screenX,
       width: window.outerWidth,
       height: window.outerHeight,
       incognito: PrivateBrowsingUtils.isWindowPrivate(window),
-
-      // We fudge on these next two.
       type: this.windowType(window),
       state,
     };
 
     if (getInfo && getInfo.populate) {
       result.tabs = TabManager.for(extension).getTabs(window);
     }
 
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -108,27 +108,35 @@ extensions.registerSchemaAPI("windows", 
             args.AppendElement(array);
           } else {
             args.AppendElement(mkstr(createData.url));
           }
         } else {
           args.AppendElement(mkstr(aboutNewTabService.newTabURL));
         }
 
-        let extraFeatures = "";
+        let features = ["chrome"];
+
+        if (createData.type === null || createData.type == "normal") {
+          features.push("dialog=no", "all");
+        } else {
+          // All other types create "popup"-type windows by default.
+          features.push("dialog", "resizable", "minimizable", "centerscreen", "titlebar", "close");
+        }
+
         if (createData.incognito !== null) {
           if (createData.incognito) {
-            extraFeatures += ",private";
+            features.push("private");
           } else {
-            extraFeatures += ",non-private";
+            features.push("non-private");
           }
         }
 
         let window = Services.ww.openWindow(null, "chrome://browser/content/browser.xul", "_blank",
-                                            "chrome,dialog=no,all" + extraFeatures, args);
+                                            features.join(","), args);
 
         if (createData.left !== null || createData.top !== null) {
           let left = createData.left !== null ? createData.left : window.screenX;
           let top = createData.top !== null ? createData.top : window.screenY;
           window.moveTo(left, top);
         }
         if (createData.width !== null || createData.height !== null) {
           let width = createData.width !== null ? createData.width : window.outerWidth;
--- a/browser/components/extensions/schemas/windows.json
+++ b/browser/components/extensions/schemas/windows.json
@@ -330,17 +330,16 @@
                 "description": "If true, opens an active window. If false, opens an inactive window."
               },
               "incognito": {
                 "type": "boolean",
                 "optional": true,
                 "description": "Whether the new window should be an incognito window."
               },
               "type": {
-                "unsupported": true,
                 "$ref": "CreateType",
                 "optional": true,
                 "description": "Specifies what type of browser window to create. The 'panel' and 'detached_panel' types create a popup unless the '--enable-panels' flag is set."
               },
               "state": {
                 "$ref": "WindowState",
                 "optional": true,
                 "description": "The initial state of the window. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'."
--- a/browser/components/extensions/test/browser/browser_ext_windows_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_create.js
@@ -17,48 +17,63 @@ add_task(function* testWindowCreate() {
 
       function checkWindow(expected) {
         return new Promise(resolve => {
           _checkWindowPromise = {resolve};
           browser.test.sendMessage("check-window", expected);
         });
       }
 
-      function createWindow(params, expected) {
+      function createWindow(params, expected, keep = false) {
         return browser.windows.create(params).then(window => {
           for (let key of Object.keys(params)) {
             if (key == "state" && os == "mac" && params.state == "normal") {
               // OS-X doesn't have a hard distinction between "normal" and
               // "maximized" states.
               browser.test.assertTrue(window.state == "normal" || window.state == "maximized",
                                       `Expected window.state (currently ${window.state}) to be "normal" but will accept "maximized"`);
             } else {
               browser.test.assertEq(params[key], window[key], `Got expected value for window.${key}`);
             }
           }
 
           return checkWindow(expected).then(() => {
+            if (keep) {
+              return window;
+            }
             if (params.state == "fullscreen" && os == "win") {
               // FIXME: Closing a fullscreen window causes a window leak in
               // Windows tests.
               return browser.windows.update(window.id, {state: "normal"}).then(() => {
                 return browser.windows.remove(window.id);
               });
             }
             return browser.windows.remove(window.id);
           });
         });
       }
 
       browser.runtime.getPlatformInfo().then(info => { os = info.os; })
       .then(() => createWindow({state: "maximized"}, {state: "STATE_MAXIMIZED"}))
       .then(() => createWindow({state: "minimized"}, {state: "STATE_MINIMIZED"}))
-      .then(() => createWindow({state: "normal"}, {state: "STATE_NORMAL"}))
+      .then(() => createWindow({state: "normal"}, {state: "STATE_NORMAL", hiddenChrome: []}))
       .then(() => createWindow({state: "fullscreen"}, {state: "STATE_FULLSCREEN"}))
       .then(() => {
+        return createWindow({type: "popup"},
+                            {hiddenChrome: ["menubar", "toolbar", "location", "directories", "status", "extrachrome"],
+                             chromeFlags: ["CHROME_OPENAS_DIALOG"]},
+                            true);
+      }).then(window => {
+        return browser.tabs.query({windowType: "popup", active: true}).then(tabs => {
+          browser.test.assertEq(1, tabs.length, "Expected only one popup");
+          browser.test.assertEq(window.id, tabs[0].windowId, "Expected new window to be returned in query");
+
+          return browser.windows.remove(window.id);
+        });
+      }).then(() => {
         browser.test.notifyPass("window-create");
       }).catch(e => {
         browser.test.fail(`${e} :: ${e.stack}`);
         browser.test.notifyFail("window-create");
       });
     },
   });
 
@@ -80,16 +95,32 @@ add_task(function* testWindowCreate() {
       if (expected.state == "STATE_NORMAL" && AppConstants.platform == "macosx") {
         ok(windowState == window.STATE_NORMAL || windowState == window.STATE_MAXIMIZED,
            `Expected windowState (currently ${windowState}) to be STATE_NORMAL but will accept STATE_MAXIMIZED`);
       } else {
         is(windowState, window[expected.state],
            `Expected window state to be ${expected.state}`);
       }
     }
+    if (expected.hiddenChrome) {
+      let chromeHidden = latestWindow.document.documentElement.getAttribute("chromehidden");
+      is(chromeHidden.trim().split(/\s+/).sort().join(" "),
+         expected.hiddenChrome.sort().join(" "),
+         "Got expected hidden chrome");
+    }
+    if (expected.chromeFlags) {
+      let {chromeFlags} = latestWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                      .getInterface(Ci.nsIDocShell)
+                                      .treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)
+                                      .getInterface(Ci.nsIXULWindow);
+      for (let flag of expected.chromeFlags) {
+        ok(chromeFlags & Ci.nsIWebBrowserChrome[flag],
+           `Expected window to have the ${flag} flag`);
+      }
+    }
 
     extension.sendMessage("checked-window");
   });
 
   yield extension.startup();
   yield extension.awaitFinish("window-create");
   yield extension.unload();