mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-04 02:09:05 +02:00
Bug 1966829 - Add a Taskbar Tabs window manager. r=mossop,cdupuis,frontend-codestyle-reviewers
This class manages the creation and removal of Taskbar Tabs windows. This maintains state necessary to determine what window a tab should return to if ejected from Taskbar Tabs. Differential Revision: https://phabricator.services.mozilla.com/D249717
This commit is contained in:
parent
771370ff73
commit
21c6063d56
7 changed files with 469 additions and 55 deletions
231
browser/components/taskbartabs/TaskbarTabsWindowManager.sys.mjs
Normal file
231
browser/components/taskbartabs/TaskbarTabsWindowManager.sys.mjs
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
/* vim: se cin sw=2 ts=2 et filetype=javascript :
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||||
|
|
||||||
|
const kTaskbarTabsWindowFeatures =
|
||||||
|
"titlebar,close,toolbar,location,personalbar=no,status,menubar=no,resizable,minimizable,scrollbars";
|
||||||
|
|
||||||
|
let lazy = {};
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
|
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
||||||
|
TaskbarTabsUtils: "resource:///modules/taskbartabs/TaskbarTabsUtils.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetters(lazy, {
|
||||||
|
WinTaskbar: ["@mozilla.org/windows-taskbar;1", "nsIWinTaskbar"],
|
||||||
|
});
|
||||||
|
|
||||||
|
ChromeUtils.defineLazyGetter(lazy, "logConsole", () => {
|
||||||
|
return console.createInstance({
|
||||||
|
prefix: "TaskbarTabs",
|
||||||
|
maxLogLevel: "Warn",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager for the lifetimes of Taskbar Tab windows.
|
||||||
|
*/
|
||||||
|
export class TaskbarTabsWindowManager {
|
||||||
|
// Count of active taskbar tabs associated to an ID.
|
||||||
|
#tabIdCount = new Map();
|
||||||
|
// Map from the tab browser permanent key to originating window ID.
|
||||||
|
#tabOriginMap = new WeakMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves an existing browser tab into a Taskbar Tab.
|
||||||
|
*
|
||||||
|
* @param {TaskbarTab} aTaskbarTab - The Taskbar Tab to replace the window with.
|
||||||
|
* @param {string} aTaskbarTab.id - ID of the Taskbar Tab.
|
||||||
|
* @param {MozTabbrowserTab} aTab - The tab to adopt as a Taskbar Tab.
|
||||||
|
* @returns {Promise} Resolves once the tab replacing window has openend.
|
||||||
|
*/
|
||||||
|
async replaceTabWithWindow({ id }, aTab) {
|
||||||
|
let originWindow = aTab.ownerGlobal;
|
||||||
|
|
||||||
|
// Save the parent window of this tab, so we can revert back if needed.
|
||||||
|
let tabId = getTabId(aTab);
|
||||||
|
let windowId = getWindowId(originWindow);
|
||||||
|
|
||||||
|
let extraOptions = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||||
|
Ci.nsIWritablePropertyBag2
|
||||||
|
);
|
||||||
|
extraOptions.setPropertyAsAString("taskbartab", id);
|
||||||
|
|
||||||
|
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||||
|
args.appendElement(aTab);
|
||||||
|
args.appendElement(extraOptions);
|
||||||
|
|
||||||
|
await this.#openWindow(id, args);
|
||||||
|
|
||||||
|
this.#tabOriginMap.set(tabId, windowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a new Taskbar Tab Window.
|
||||||
|
*
|
||||||
|
* @param {TaskbarTab} aTaskbarTab - The Taskbar Tab to open.
|
||||||
|
* @returns {Promise} Resolves once the window has opened.
|
||||||
|
*/
|
||||||
|
async openWindow(aTaskbarTab) {
|
||||||
|
let url = Cc["@mozilla.org/supports-string;1"].createInstance(
|
||||||
|
Ci.nsISupportsString
|
||||||
|
);
|
||||||
|
url.data = aTaskbarTab.startUrl;
|
||||||
|
|
||||||
|
let extraOptions = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
||||||
|
Ci.nsIWritablePropertyBag2
|
||||||
|
);
|
||||||
|
extraOptions.setPropertyAsAString("taskbartab", aTaskbarTab.id);
|
||||||
|
|
||||||
|
let userContextId = Cc["@mozilla.org/supports-PRUint32;1"].createInstance(
|
||||||
|
Ci.nsISupportsPRUint32
|
||||||
|
);
|
||||||
|
userContextId.data = aTaskbarTab.userContextId;
|
||||||
|
|
||||||
|
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||||
|
args.appendElement(url);
|
||||||
|
args.appendElement(extraOptions);
|
||||||
|
args.appendElement(null);
|
||||||
|
args.appendElement(null);
|
||||||
|
args.appendElement(undefined);
|
||||||
|
args.appendElement(userContextId);
|
||||||
|
args.appendElement(null);
|
||||||
|
args.appendElement(null);
|
||||||
|
args.appendElement(Services.scriptSecurityManager.getSystemPrincipal());
|
||||||
|
|
||||||
|
await this.#openWindow(aTaskbarTab.id, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles common window opening behavior for Taskbar Tabs.
|
||||||
|
*
|
||||||
|
* @param {string} aId - ID of the Taskbar Tab to use as the window AUMID.
|
||||||
|
* @param {nsIMutableArray} aArgs - `args` to pass to the opening window.
|
||||||
|
* @returns {Promise} Resolves once window has opened and tab count has been
|
||||||
|
* incremented.
|
||||||
|
*/
|
||||||
|
async #openWindow(aId, aArgs) {
|
||||||
|
let win = await lazy.BrowserWindowTracker.promiseOpenWindow({
|
||||||
|
args: aArgs,
|
||||||
|
features: kTaskbarTabsWindowFeatures,
|
||||||
|
all: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
lazy.WinTaskbar.setGroupIdForWindow(win, aId);
|
||||||
|
win.focus();
|
||||||
|
|
||||||
|
let tabIdCount = this.#tabIdCount.get(aId) ?? 0;
|
||||||
|
this.#tabIdCount.set(aId, ++tabIdCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts a web app to a tab in a regular Firefox window. We will try to use
|
||||||
|
* the window the taskbar tab originated from, if that's not avaliable, we
|
||||||
|
* will use the most recently active window. If no window is avalaible, a new
|
||||||
|
* one will be opened.
|
||||||
|
*
|
||||||
|
* @param {DOMWindow} aWindow - A Tasbkar Tab window.
|
||||||
|
*/
|
||||||
|
async ejectWindow(aWindow) {
|
||||||
|
lazy.logConsole.info("Ejecting window from Taskbar Tabs.");
|
||||||
|
|
||||||
|
let taskbarTabId = lazy.TaskbarTabsUtils.getTaskbarTabIdFromWindow(aWindow);
|
||||||
|
if (!taskbarTabId) {
|
||||||
|
throw new Error("No Taskbar Tab ID found on window.");
|
||||||
|
} else {
|
||||||
|
lazy.logConsole.debug(`Taskbar Tab ID is ${taskbarTabId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let windowList = lazy.BrowserWindowTracker.getOrderedWindows({
|
||||||
|
private: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// A Taskbar Tab should only contain one tab, but iterate over the browser's
|
||||||
|
// tabs just in case one snuck in.
|
||||||
|
for (const tab of aWindow.gBrowser.tabs) {
|
||||||
|
let tabId = getTabId(tab);
|
||||||
|
let originWindowId = this.#tabOriginMap.get(tabId);
|
||||||
|
|
||||||
|
let win =
|
||||||
|
// Find the originating window for the Taskbar Tab if it still exists.
|
||||||
|
windowList.find(window => {
|
||||||
|
let windowId = getWindowId(window);
|
||||||
|
let matching = windowId === originWindowId;
|
||||||
|
if (matching) {
|
||||||
|
lazy.logConsole.debug(
|
||||||
|
`Ejecting into originating window: ${windowId}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return matching;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!win) {
|
||||||
|
// Otherwise the most recent non-Taskbar Tabs window interacted with.
|
||||||
|
win = lazy.BrowserWindowTracker.getTopWindow({
|
||||||
|
private: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
lazy.logConsole.debug(`Ejecting into top window.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
// Set this tab to the last tab position of the window.
|
||||||
|
win.gBrowser.adoptTab(tab, {
|
||||||
|
tabIndex: win.gBrowser.openTabs.length,
|
||||||
|
selectTab: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
lazy.logConsole.debug(
|
||||||
|
"No originating or existing browser window found, ejecting into newly created window."
|
||||||
|
);
|
||||||
|
win = await lazy.BrowserWindowTracker.promiseOpenWindow({ args: tab });
|
||||||
|
}
|
||||||
|
|
||||||
|
win.focus();
|
||||||
|
|
||||||
|
this.#tabOriginMap.delete(tabId);
|
||||||
|
let tabIdCount = this.#tabIdCount.get(taskbarTabId);
|
||||||
|
if (tabIdCount > 0) {
|
||||||
|
this.#tabIdCount.set(taskbarTabId, --tabIdCount);
|
||||||
|
} else {
|
||||||
|
lazy.logConsole.error("Tab count should have been greater than 0.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a count of the current windows associated to a Taskbar Tab.
|
||||||
|
*
|
||||||
|
* @param {string} aId - The Taskbar Tab ID.
|
||||||
|
* @returns {integer} Count of windows associated to the Taskbar Tab ID.
|
||||||
|
*/
|
||||||
|
getCountForId(aId) {
|
||||||
|
return this.#tabIdCount.get(aId) ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the browser tab's ID.
|
||||||
|
*
|
||||||
|
* @param {MozTabbrowserTab} aTab - Tab to retrieve the ID from.
|
||||||
|
* @returns {object} The permanent key identifying the tab.
|
||||||
|
*/
|
||||||
|
function getTabId(aTab) {
|
||||||
|
return aTab.permanentKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the window ID.
|
||||||
|
*
|
||||||
|
* @param {DOMWindow} aWindow
|
||||||
|
* @returns {string} A unique string identifying the window.
|
||||||
|
*/
|
||||||
|
function getWindowId(aWindow) {
|
||||||
|
return aWindow.docShell.outerWindowID;
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ EXTRA_JS_MODULES.taskbartabs += [
|
||||||
"TaskbarTabUI.sys.mjs",
|
"TaskbarTabUI.sys.mjs",
|
||||||
"TaskbarTabsRegistry.sys.mjs",
|
"TaskbarTabsRegistry.sys.mjs",
|
||||||
"TaskbarTabsUtils.sys.mjs",
|
"TaskbarTabsUtils.sys.mjs",
|
||||||
|
"TaskbarTabsWindowManager.sys.mjs",
|
||||||
]
|
]
|
||||||
|
|
||||||
JAR_MANIFESTS += ["jar.mn"]
|
JAR_MANIFESTS += ["jar.mn"]
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,7 @@ support-files = [
|
||||||
"dummy_page.html",
|
"dummy_page.html",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
["browser_taskbarTabs_windowManager.js"]
|
||||||
|
|
||||||
["browser_taskbarTabs_windowTracker.js"]
|
["browser_taskbarTabs_windowTracker.js"]
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,6 @@
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
ChromeUtils.defineESModuleGetters(this, {
|
|
||||||
AppConstants: "resource://gre/modules/AppConstants.sys.mjs",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Given a window, check if it meets all requirements
|
// Given a window, check if it meets all requirements
|
||||||
// of the taskbar tab chrome UI
|
// of the taskbar tab chrome UI
|
||||||
function checkWindowChrome(win) {
|
function checkWindowChrome(win) {
|
||||||
|
|
@ -104,33 +100,12 @@ async function checkHamburgerMenu(win) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_task(async function testWindowChrome() {
|
// Creates a Taskbar Tab window and verifies UI elements match expectations.
|
||||||
let win = await openTaskbarTabWindow();
|
add_task(async function testOpenWindowChrome() {
|
||||||
|
const win = await openTaskbarTabWindow();
|
||||||
|
|
||||||
checkWindowChrome(win);
|
checkWindowChrome(win);
|
||||||
await checkHamburgerMenu(win);
|
await checkHamburgerMenu(win);
|
||||||
await BrowserTestUtils.closeWindow(win);
|
|
||||||
|
|
||||||
// Simulate opening a taskbar tab window via
|
|
||||||
// command line flag
|
|
||||||
let cmdLine = Cu.createCommandLine(
|
|
||||||
["-taskbar-tab", "about:blank"],
|
|
||||||
null,
|
|
||||||
Ci.nsICommandLine.STATE_INITIAL_LAUNCH
|
|
||||||
);
|
|
||||||
|
|
||||||
let newWinPromise = BrowserTestUtils.waitForNewWindow({
|
|
||||||
url: "about:blank",
|
|
||||||
});
|
|
||||||
|
|
||||||
let cmdLineHandler = Cc["@mozilla.org/browser/taskbar-tabs-clh;1"].getService(
|
|
||||||
Ci.nsICommandLineHandler
|
|
||||||
);
|
|
||||||
cmdLineHandler.handle(cmdLine);
|
|
||||||
|
|
||||||
win = await newWinPromise;
|
|
||||||
|
|
||||||
checkWindowChrome(win);
|
|
||||||
await checkHamburgerMenu(win);
|
|
||||||
await BrowserTestUtils.closeWindow(win);
|
await BrowserTestUtils.closeWindow(win);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(this, {
|
||||||
|
TaskbarTabsUtils: "resource:///modules/taskbartabs/TaskbarTabsUtils.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||||
|
WinTaskbar: ["@mozilla.org/windows-taskbar;1", "nsIWinTaskbar"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const registry = new TaskbarTabsRegistry();
|
||||||
|
|
||||||
|
const url1 = Services.io.newURI("https://example.com");
|
||||||
|
const userContextId1 = 0;
|
||||||
|
const taskbarTab1 = registry.findOrCreateTaskbarTab(url1, userContextId1);
|
||||||
|
const id1 = taskbarTab1.id;
|
||||||
|
|
||||||
|
const url2 = Services.io.newURI("https://subdomain.example.com");
|
||||||
|
const userContextId2 = 1;
|
||||||
|
const taskbarTab2 = registry.findOrCreateTaskbarTab(url2, userContextId2);
|
||||||
|
const id2 = taskbarTab2.id;
|
||||||
|
|
||||||
|
add_setup(async () => {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["network.dns.localDomains", [url1.host, url2.host]]],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_count_for_id() {
|
||||||
|
const wm = new TaskbarTabsWindowManager();
|
||||||
|
let testWindowCount = (aCount1, aCount2) => {
|
||||||
|
is(
|
||||||
|
wm.getCountForId(id1),
|
||||||
|
aCount1,
|
||||||
|
`${aCount1} Taskbar Tab window(s) should exist for id ${id1}`
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
wm.getCountForId(id2),
|
||||||
|
aCount2,
|
||||||
|
`${aCount2} Taskbar Tab window(s) should exist for id ${id2}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
testWindowCount(0, 0);
|
||||||
|
|
||||||
|
let windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab1);
|
||||||
|
let win1_to_eject = await windowPromise;
|
||||||
|
|
||||||
|
testWindowCount(1, 0);
|
||||||
|
|
||||||
|
windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab1);
|
||||||
|
let win2 = await windowPromise;
|
||||||
|
|
||||||
|
testWindowCount(2, 0);
|
||||||
|
|
||||||
|
windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab2);
|
||||||
|
let win3_to_eject = await windowPromise;
|
||||||
|
|
||||||
|
testWindowCount(2, 1);
|
||||||
|
|
||||||
|
let tab1_adopted = await BrowserTestUtils.addTab(window.gBrowser, url1.spec);
|
||||||
|
windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.replaceTabWithWindow(taskbarTab1, tab1_adopted);
|
||||||
|
let win4 = await windowPromise;
|
||||||
|
|
||||||
|
testWindowCount(3, 1);
|
||||||
|
|
||||||
|
let tabOpenPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
window.gBrowser.tabContainer,
|
||||||
|
"TabOpen"
|
||||||
|
);
|
||||||
|
await wm.ejectWindow(win1_to_eject);
|
||||||
|
let tab2 = (await tabOpenPromise).target;
|
||||||
|
|
||||||
|
testWindowCount(2, 1);
|
||||||
|
|
||||||
|
tabOpenPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
window.gBrowser.tabContainer,
|
||||||
|
"TabOpen"
|
||||||
|
);
|
||||||
|
await wm.ejectWindow(win3_to_eject);
|
||||||
|
let tab3 = (await tabOpenPromise).target;
|
||||||
|
|
||||||
|
testWindowCount(2, 0);
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab2);
|
||||||
|
BrowserTestUtils.removeTab(tab3);
|
||||||
|
await Promise.all([
|
||||||
|
BrowserTestUtils.closeWindow(win2),
|
||||||
|
BrowserTestUtils.closeWindow(win4),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_user_context_id() {
|
||||||
|
function checkUserContextId(win, taskbarTab) {
|
||||||
|
is(
|
||||||
|
win.gBrowser.selectedTab.userContextId,
|
||||||
|
taskbarTab.userContextId,
|
||||||
|
"Tab's userContextId should match that for the Taskbar Tab."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wm = new TaskbarTabsWindowManager();
|
||||||
|
|
||||||
|
let testForTaskbarTab = async taskbarTab => {
|
||||||
|
let windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab);
|
||||||
|
let win = await windowPromise;
|
||||||
|
checkUserContextId(win, taskbarTab);
|
||||||
|
|
||||||
|
const tabOpenPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
window.gBrowser.tabContainer,
|
||||||
|
"TabOpen"
|
||||||
|
);
|
||||||
|
await wm.ejectWindow(win);
|
||||||
|
let tab = (await tabOpenPromise).target;
|
||||||
|
win = tab.ownerGlobal;
|
||||||
|
checkUserContextId(win, taskbarTab);
|
||||||
|
|
||||||
|
windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.replaceTabWithWindow(taskbarTab, tab);
|
||||||
|
win = await windowPromise;
|
||||||
|
checkUserContextId(win, taskbarTab);
|
||||||
|
|
||||||
|
await BrowserTestUtils.closeWindow(win);
|
||||||
|
};
|
||||||
|
|
||||||
|
await testForTaskbarTab(taskbarTab1);
|
||||||
|
await testForTaskbarTab(taskbarTab2);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_eject_window_selected_tab() {
|
||||||
|
const wm = new TaskbarTabsWindowManager();
|
||||||
|
|
||||||
|
let windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab1);
|
||||||
|
let win = await windowPromise;
|
||||||
|
|
||||||
|
const tabOpenPromise = BrowserTestUtils.waitForEvent(
|
||||||
|
window.gBrowser.tabContainer,
|
||||||
|
"TabOpen"
|
||||||
|
);
|
||||||
|
await wm.ejectWindow(win);
|
||||||
|
let tab = (await tabOpenPromise).target;
|
||||||
|
|
||||||
|
is(
|
||||||
|
tab,
|
||||||
|
window.gBrowser.selectedTab,
|
||||||
|
"The ejected Taskbar Tab should be the selected tab."
|
||||||
|
);
|
||||||
|
|
||||||
|
await BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_window_aumid() {
|
||||||
|
const wm = new TaskbarTabsWindowManager();
|
||||||
|
|
||||||
|
let windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.openWindow(taskbarTab1);
|
||||||
|
let winOpen = await windowPromise;
|
||||||
|
|
||||||
|
is(
|
||||||
|
TaskbarTabsUtils.getTaskbarTabIdFromWindow(winOpen),
|
||||||
|
taskbarTab1.id,
|
||||||
|
"The window's `tasbkartab` attribute should match the Taskbar Tab ID when opened."
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
WinTaskbar.getGroupIdForWindow(winOpen),
|
||||||
|
taskbarTab1.id,
|
||||||
|
"The window AUMID should match the Taskbar Tab ID when opened."
|
||||||
|
);
|
||||||
|
|
||||||
|
let tab1_adopted = await BrowserTestUtils.addTab(window.gBrowser, url1.spec);
|
||||||
|
windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
|
await wm.replaceTabWithWindow(taskbarTab1, tab1_adopted);
|
||||||
|
let winReplace = await windowPromise;
|
||||||
|
|
||||||
|
is(
|
||||||
|
TaskbarTabsUtils.getTaskbarTabIdFromWindow(winReplace),
|
||||||
|
taskbarTab1.id,
|
||||||
|
"The window's `tasbkartab` attribute should match the Taskbar Tab ID when a tab was replaced with a Tasbkar Tab window."
|
||||||
|
);
|
||||||
|
is(
|
||||||
|
WinTaskbar.getGroupIdForWindow(winReplace),
|
||||||
|
taskbarTab1.id,
|
||||||
|
"The window AUMID should match the Taskbar Tab ID when a tab was replaced with a Tasbkar Tab window."
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
BrowserTestUtils.closeWindow(winOpen),
|
||||||
|
BrowserTestUtils.closeWindow(winReplace),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
@ -2,41 +2,39 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(this, {
|
||||||
|
TaskbarTabsRegistry:
|
||||||
|
"resource:///modules/taskbartabs/TaskbarTabsRegistry.sys.mjs",
|
||||||
|
TaskbarTabsWindowManager:
|
||||||
|
"resource:///modules/taskbartabs/TaskbarTabsWindowManager.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a web app window with the given tab,
|
* Creates a web app window with the given tab,
|
||||||
* then returns the window object for testing.
|
* then returns the window object for testing.
|
||||||
*
|
*
|
||||||
* @param {Tab} tab
|
* @param {Tab} aTab
|
||||||
* The tab that the web app should open with,
|
* The tab that the web app should open with
|
||||||
* about:blank will be opened if this value is null.
|
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
* The web app window object.
|
* The web app window object.
|
||||||
*/
|
*/
|
||||||
async function openTaskbarTabWindow(tab = null) {
|
async function openTaskbarTabWindow(aTab = null) {
|
||||||
let extraOptions = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
const url = Services.io.newURI("https://example.com");
|
||||||
Ci.nsIWritablePropertyBag2
|
const userContextId = 0;
|
||||||
);
|
|
||||||
extraOptions.setPropertyAsBool("taskbartab", true);
|
|
||||||
|
|
||||||
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
const registry = new TaskbarTabsRegistry();
|
||||||
|
const taskbarTab = registry.findOrCreateTaskbarTab(url, userContextId);
|
||||||
|
const windowManager = new TaskbarTabsWindowManager();
|
||||||
|
|
||||||
args.appendElement(tab);
|
const windowPromise = BrowserTestUtils.waitForNewWindow();
|
||||||
args.appendElement(extraOptions);
|
|
||||||
args.appendElement(null);
|
|
||||||
|
|
||||||
// Simulate opening a taskbar tab window
|
if (aTab) {
|
||||||
let win = Services.ww.openWindow(
|
windowManager.replaceTabWithWindow(taskbarTab, aTab);
|
||||||
null,
|
} else {
|
||||||
AppConstants.BROWSER_CHROME_URL,
|
windowManager.openWindow(taskbarTab);
|
||||||
"_blank",
|
}
|
||||||
"chrome,dialog=no,titlebar,close,toolbar,location,personalbar=no,status,menubar=no,resizable,minimizable,scrollbars",
|
|
||||||
args
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
return await windowPromise;
|
||||||
win.addEventListener("load", resolve, { once: true });
|
|
||||||
});
|
|
||||||
await win.delayedStartupPromise;
|
|
||||||
|
|
||||||
return win;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,9 @@ export const BrowserWindowTracker = {
|
||||||
* True to make the window a private browsing window.
|
* True to make the window a private browsing window.
|
||||||
* @param {String} [options.features]
|
* @param {String} [options.features]
|
||||||
* Additional window features to give the new window.
|
* Additional window features to give the new window.
|
||||||
|
* @param {boolean} [options.all]
|
||||||
|
* True if "all" should be included as a window feature. If omitted, defaults
|
||||||
|
* to true.
|
||||||
* @param {nsIArray | nsISupportsString} [options.args]
|
* @param {nsIArray | nsISupportsString} [options.args]
|
||||||
* Arguments to pass to the new window.
|
* Arguments to pass to the new window.
|
||||||
* @param {boolean} [options.remote]
|
* @param {boolean} [options.remote]
|
||||||
|
|
@ -293,11 +296,15 @@ export const BrowserWindowTracker = {
|
||||||
openerWindow = undefined,
|
openerWindow = undefined,
|
||||||
private: isPrivate = false,
|
private: isPrivate = false,
|
||||||
features = undefined,
|
features = undefined,
|
||||||
|
all = true,
|
||||||
args = null,
|
args = null,
|
||||||
remote = undefined,
|
remote = undefined,
|
||||||
fission = undefined,
|
fission = undefined,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
let windowFeatures = "chrome,dialog=no,all";
|
let windowFeatures = "chrome,dialog=no";
|
||||||
|
if (all) {
|
||||||
|
windowFeatures += ",all";
|
||||||
|
}
|
||||||
if (features) {
|
if (features) {
|
||||||
windowFeatures += `,${features}`;
|
windowFeatures += `,${features}`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue