Bug 1253133: [webext] Support changing window geometry via windows.update. r?aswan
MozReview-Commit-ID: LQGXyB9WuiI
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -661,16 +661,30 @@ global.WindowManager = {
if (chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG) {
return "popup";
}
return "normal";
},
+ updateGeometry(window, options) {
+ if (options.left !== null || options.top !== null) {
+ let left = options.left !== null ? options.left : window.screenX;
+ let top = options.top !== null ? options.top : window.screenY;
+ window.moveTo(left, top);
+ }
+
+ if (options.width !== null || options.height !== null) {
+ let width = options.width !== null ? options.width : window.outerWidth;
+ let height = options.height !== null ? options.height : window.outerHeight;
+ window.resizeTo(width, height);
+ }
+ },
+
getId(window) {
if (this._windows.has(window)) {
return this._windows.get(window);
}
let id = this._nextId++;
this._windows.set(window, id);
return id;
},
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -128,26 +128,17 @@ extensions.registerSchemaAPI("windows",
} else {
features.push("non-private");
}
}
let window = Services.ww.openWindow(null, "chrome://browser/content/browser.xul", "_blank",
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;
- let height = createData.height !== null ? createData.height : window.outerHeight;
- window.resizeTo(width, height);
- }
+ WindowManager.updateGeometry(window, createData);
// TODO: focused, type
return new Promise(resolve => {
window.addEventListener("load", function listener() {
window.removeEventListener("load", listener);
if (createData.state == "maximized" || createData.state == "normal" ||
@@ -171,33 +162,34 @@ extensions.registerSchemaAPI("windows",
resolve();
});
}).then(() => {
return WindowManager.convert(extension, window);
});
},
update: function(windowId, updateInfo) {
- // TODO: When we support size/position updates:
- // if (updateInfo.state !== null && updateInfo.state != "normal") {
- // if (updateInfo.left !== null || updateInfo.top !== null ||
- // updateInfo.width !== null || updateInfo.height !== null) {
- // return Promise.reject({message: `"state": "${updateInfo.state}" may not be combined with "left", "top", "width", or "height"`});
- // }
- // }
+ if (updateInfo.state !== null && updateInfo.state != "normal") {
+ if (updateInfo.left !== null || updateInfo.top !== null ||
+ updateInfo.width !== null || updateInfo.height !== null) {
+ return Promise.reject({message: `"state": "${updateInfo.state}" may not be combined with "left", "top", "width", or "height"`});
+ }
+ }
let window = WindowManager.getWindow(windowId, context);
if (updateInfo.focused) {
Services.focus.activeWindow = window;
}
if (updateInfo.state !== null) {
WindowManager.setState(window, updateInfo.state);
}
+ WindowManager.updateGeometry(window, updateInfo);
+
// TODO: All the other properties, focused=false...
return Promise.resolve(WindowManager.convert(extension, window));
},
remove: function(windowId) {
let window = WindowManager.getWindow(windowId, context);
window.close();
--- a/browser/components/extensions/schemas/windows.json
+++ b/browser/components/extensions/schemas/windows.json
@@ -372,36 +372,32 @@
"name": "windowId",
"minimum": -2
},
{
"type": "object",
"name": "updateInfo",
"properties": {
"left": {
- "unsupported": true,
"type": "integer",
"optional": true,
"description": "The offset from the left edge of the screen to move the window to in pixels. This value is ignored for panels."
},
"top": {
- "unsupported": true,
"type": "integer",
"optional": true,
"description": "The offset from the top edge of the screen to move the window to in pixels. This value is ignored for panels."
},
"width": {
- "unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
"description": "The width to resize the window to in pixels. This value is ignored for panels."
},
"height": {
- "unsupported": true,
"type": "integer",
"minimum": 0,
"optional": true,
"description": "The height to resize the window to in pixels. This value is ignored for panels."
},
"focused": {
"type": "boolean",
"optional": true,
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -52,14 +52,15 @@ support-files =
[browser_ext_tabs_move_window.js]
[browser_ext_tabs_move_window_multiple.js]
[browser_ext_tabs_move_window_pinned.js]
[browser_ext_tabs_onHighlighted.js]
[browser_ext_windows_create.js]
tags = fullscreen
[browser_ext_windows_create_tabId.js]
[browser_ext_windows.js]
+[browser_ext_windows_size.js]
[browser_ext_windows_update.js]
tags = fullscreen
[browser_ext_contentscript_connect.js]
[browser_ext_tab_runtimeConnect.js]
[browser_ext_topwindowid.js]
[browser_ext_webNavigation_getFrames.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_windows_size.js
@@ -0,0 +1,99 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* testWindowCreate() {
+ let extension = ExtensionTestUtils.loadExtension({
+ background() {
+ let _checkWindowPromise;
+ browser.test.onMessage.addListener((msg, arg) => {
+ if (msg == "checked-window") {
+ _checkWindowPromise.resolve(arg);
+ _checkWindowPromise = null;
+ }
+ });
+
+ let windowId;
+
+ function checkWindow(expected) {
+ return new Promise(resolve => {
+ _checkWindowPromise = {resolve};
+ browser.test.sendMessage("check-window", expected);
+ }).then(geom => {
+ browser.test.log("Check actual window size");
+
+ for (let key of ["left", "top", "width", "height"]) {
+ browser.test.assertEq(expected[key], geom[key], `Expected '${key}' value`);
+ }
+
+ return browser.windows.get(windowId);
+ }).then(geom => {
+ browser.test.log("Check API-reported window size");
+
+ for (let key of ["left", "top", "width", "height"]) {
+ browser.test.assertEq(expected[key], geom[key], `Expected '${key}' value`);
+ }
+ });
+ }
+
+ let geom = {left: 100, top: 100, width: 500, height: 100};
+
+ return browser.windows.create(geom).then(window => {
+ windowId = window.id;
+
+ return checkWindow(geom);
+ }).then(() => {
+ let update = {left: 50, width: 600};
+ Object.assign(geom, update);
+
+ return browser.windows.update(windowId, update);
+ }).then(() => {
+ return checkWindow(geom);
+ }).then(() => {
+ let update = {top: 50, height: 200};
+ Object.assign(geom, update);
+
+ return browser.windows.update(windowId, update);
+ }).then(() => {
+ return checkWindow(geom);
+ }).then(() => {
+ geom = {left: 200, top: 200, width: 800, height: 600};
+
+ return browser.windows.update(windowId, geom);
+ }).then(() => {
+ return checkWindow(geom);
+ }).then(() => {
+ return browser.windows.remove(windowId);
+ }).then(() => {
+ browser.test.notifyPass("window-size");
+ }).catch(e => {
+ browser.test.fail(`${e} :: ${e.stack}`);
+ browser.test.notifyFail("window-size");
+ });
+ },
+ });
+
+ let latestWindow;
+ let windowListener = (window, topic) => {
+ if (topic == "domwindowopened") {
+ latestWindow = window;
+ }
+ };
+ Services.ww.registerNotification(windowListener);
+
+ extension.onMessage("check-window", expected => {
+ extension.sendMessage("checked-window", {
+ top: latestWindow.screenY,
+ left: latestWindow.screenX,
+ width: latestWindow.outerWidth,
+ height: latestWindow.outerHeight,
+ });
+ });
+
+ yield extension.startup();
+ yield extension.awaitFinish("window-size");
+ yield extension.unload();
+
+ Services.ww.unregisterNotification(windowListener);
+ latestWindow = null;
+});
--- a/browser/components/extensions/test/browser/browser_ext_windows_update.js
+++ b/browser/components/extensions/test/browser/browser_ext_windows_update.js
@@ -120,8 +120,47 @@ add_task(function* testWindowUpdate() {
extension.sendMessage("checked-window");
});
yield extension.startup();
yield extension.awaitFinish("window-update");
yield extension.unload();
});
+
+
+// Tests that incompatible parameters can't be used together.
+add_task(function* testWindowUpdateParams() {
+ let extension = ExtensionTestUtils.loadExtension({
+ background() {
+ function* getCalls() {
+ for (let state of ["minimized", "maximized", "fullscreen"]) {
+ for (let param of ["left", "top", "width", "height"]) {
+ let expected = `"state": "${state}" may not be combined with "left", "top", "width", or "height"`;
+
+ let windowId = browser.windows.WINDOW_ID_CURRENT;
+ yield browser.windows.update(windowId, {state, [param]: 100}).then(
+ val => {
+ browser.test.fail(`Expected error but got "${val}" instead`);
+ },
+ error => {
+ browser.test.assertTrue(
+ error.message.includes(expected),
+ `Got expected error (got: '${error.message}', expected: '${expected}'`);
+ });
+ }
+ }
+ }
+
+ Promise.all(getCalls()).then(() => {
+ browser.test.notifyPass("window-update-params");
+ }).catch(e => {
+ browser.test.fail(`${e} :: ${e.stack}`);
+ browser.test.notifyFail("window-update-params");
+ });
+ },
+ });
+
+ yield extension.startup();
+ yield extension.awaitFinish("window-update-params");
+ yield extension.unload();
+});
+