mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1779559 - Do this in toolkit instead. r=Gijs
This simplifies a bit the tabbrowser/tab switcher code, and makes it work in all windows. The WPT failures are due to bug 1780212. Differential Revision: https://phabricator.services.mozilla.com/D151822
This commit is contained in:
parent
1f6f403400
commit
0170e759f8
@ -42,8 +42,7 @@
|
||||
|
||||
Services.els.addSystemEventListener(document, "keydown", this, false);
|
||||
Services.els.addSystemEventListener(document, "keypress", this, false);
|
||||
window.addEventListener("sizemodechange", this);
|
||||
window.addEventListener("occlusionstatechange", this);
|
||||
document.addEventListener("visibilitychange", this);
|
||||
window.addEventListener("framefocusrequested", this);
|
||||
|
||||
this.tabContainer.init();
|
||||
@ -1101,9 +1100,7 @@
|
||||
oldBrowser.removeAttribute("primary");
|
||||
oldBrowser.docShellIsActive = false;
|
||||
newBrowser.setAttribute("primary", "true");
|
||||
newBrowser.docShellIsActive =
|
||||
window.windowState != window.STATE_MINIMIZED &&
|
||||
!window.isFullyOccluded;
|
||||
newBrowser.docShellIsActive = !document.hidden;
|
||||
}
|
||||
|
||||
this._selectedBrowser = newBrowser;
|
||||
@ -5316,9 +5313,7 @@
|
||||
return this._switcher.shouldActivateDocShell(aBrowser);
|
||||
}
|
||||
return (
|
||||
(aBrowser == this.selectedBrowser &&
|
||||
window.windowState != window.STATE_MINIMIZED &&
|
||||
!window.isFullyOccluded) ||
|
||||
(aBrowser == this.selectedBrowser && !document.hidden) ||
|
||||
this._printPreviewBrowsers.has(aBrowser) ||
|
||||
this.PictureInPicture.isOriginatingBrowser(aBrowser)
|
||||
);
|
||||
@ -5633,17 +5628,11 @@
|
||||
aEvent.preventDefault();
|
||||
break;
|
||||
}
|
||||
case "sizemodechange":
|
||||
case "occlusionstatechange":
|
||||
if (aEvent.target == window) {
|
||||
const inactive =
|
||||
window.windowState == window.STATE_MINIMIZED ||
|
||||
window.isFullyOccluded;
|
||||
window.browsingContext.isActive = !inactive;
|
||||
if (!this._switcher) {
|
||||
this.selectedBrowser.preserveLayers(inactive);
|
||||
this.selectedBrowser.docShellIsActive = !inactive;
|
||||
}
|
||||
case "visibilitychange":
|
||||
const inactive = document.hidden;
|
||||
if (!this._switcher) {
|
||||
this.selectedBrowser.preserveLayers(inactive);
|
||||
this.selectedBrowser.docShellIsActive = !inactive;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5770,8 +5759,7 @@
|
||||
false
|
||||
);
|
||||
}
|
||||
window.removeEventListener("sizemodechange", this);
|
||||
window.removeEventListener("occlusionstatechange", this);
|
||||
document.removeEventListener("visibilitychange", this);
|
||||
window.removeEventListener("framefocusrequested", this);
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
|
@ -17,6 +17,15 @@ registerCleanupFunction(async function() {
|
||||
}
|
||||
});
|
||||
|
||||
add_setup(async () => {
|
||||
// Disable window occlusion. See bug 1733955 / bug 1779559.
|
||||
if (navigator.platform.indexOf("Win") == 0) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["widget.windows.window_occlusion_tracking.enabled", false]],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function checkStateDuringPrefFlips() {
|
||||
ok(
|
||||
Services.prefs.getBoolPref(kDownloadAutoHidePref),
|
||||
|
@ -158,10 +158,9 @@ class AsyncTabSwitcher {
|
||||
this.window.addEventListener("MozLayerTreeReady", this);
|
||||
this.window.addEventListener("MozLayerTreeCleared", this);
|
||||
this.window.addEventListener("TabRemotenessChange", this);
|
||||
this.window.addEventListener("sizemodechange", this);
|
||||
this.window.addEventListener("occlusionstatechange", this);
|
||||
this.window.addEventListener("SwapDocShells", this, true);
|
||||
this.window.addEventListener("EndSwapDocShells", this, true);
|
||||
this.window.document.addEventListener("visibilitychange", this);
|
||||
|
||||
let initialTab = this.requestedTab;
|
||||
let initialBrowser = initialTab.linkedBrowser;
|
||||
@ -175,7 +174,7 @@ class AsyncTabSwitcher {
|
||||
// browser. Let's clear it.
|
||||
initialBrowser.preserveLayers(false);
|
||||
|
||||
if (!this.minimizedOrFullyOccluded) {
|
||||
if (!this.windowHidden) {
|
||||
this.log("Initial tab is loaded?: " + tabIsLoaded);
|
||||
this.setTabState(
|
||||
initialTab,
|
||||
@ -204,10 +203,9 @@ class AsyncTabSwitcher {
|
||||
this.window.removeEventListener("MozLayerTreeReady", this);
|
||||
this.window.removeEventListener("MozLayerTreeCleared", this);
|
||||
this.window.removeEventListener("TabRemotenessChange", this);
|
||||
this.window.removeEventListener("sizemodechange", this);
|
||||
this.window.removeEventListener("occlusionstatechange", this);
|
||||
this.window.removeEventListener("SwapDocShells", this, true);
|
||||
this.window.removeEventListener("EndSwapDocShells", this, true);
|
||||
this.window.document.removeEventListener("visibilitychange", this);
|
||||
|
||||
this.tabbrowser._switcher = null;
|
||||
}
|
||||
@ -273,7 +271,7 @@ class AsyncTabSwitcher {
|
||||
let browser = tab.linkedBrowser;
|
||||
let { remoteTab } = browser.frameLoader;
|
||||
if (state == this.STATE_LOADING) {
|
||||
this.assert(!this.minimizedOrFullyOccluded);
|
||||
this.assert(!this.windowHidden);
|
||||
|
||||
// If we're not in the process of warming this tab, we
|
||||
// don't need to delay activating its DocShell.
|
||||
@ -317,11 +315,8 @@ class AsyncTabSwitcher {
|
||||
}
|
||||
}
|
||||
|
||||
get minimizedOrFullyOccluded() {
|
||||
return (
|
||||
this.window.windowState == this.window.STATE_MINIMIZED ||
|
||||
this.window.isFullyOccluded
|
||||
);
|
||||
get windowHidden() {
|
||||
return this.window.document.hidden;
|
||||
}
|
||||
|
||||
get tabLayerCache() {
|
||||
@ -339,7 +334,7 @@ class AsyncTabSwitcher {
|
||||
this.assert(!this.loadingTab);
|
||||
this.assert(this.lastVisibleTab === this.requestedTab);
|
||||
this.assert(
|
||||
this.minimizedOrFullyOccluded ||
|
||||
this.windowHidden ||
|
||||
this.getTabState(this.requestedTab) == this.STATE_LOADED
|
||||
);
|
||||
|
||||
@ -385,7 +380,7 @@ class AsyncTabSwitcher {
|
||||
|
||||
let fl = requestedBrowser.frameLoader;
|
||||
shouldBeBlank =
|
||||
!this.minimizedOrFullyOccluded &&
|
||||
!this.windowHidden &&
|
||||
(!fl.remoteTab ||
|
||||
(!hasSufficientlyLoaded && !fl.remoteTab.hasPresented));
|
||||
|
||||
@ -393,7 +388,7 @@ class AsyncTabSwitcher {
|
||||
let flag = shouldBeBlank ? "blank" : "nonblank";
|
||||
this.addLogFlag(
|
||||
flag,
|
||||
this.minimizedOrFullyOccluded,
|
||||
this.windowHidden,
|
||||
fl.remoteTab,
|
||||
isBusy,
|
||||
isLocalAbout,
|
||||
@ -439,7 +434,7 @@ class AsyncTabSwitcher {
|
||||
// Show or hide the spinner as needed.
|
||||
let needSpinner =
|
||||
this.getTabState(showTab) != this.STATE_LOADED &&
|
||||
!this.minimizedOrFullyOccluded &&
|
||||
!this.windowHidden &&
|
||||
!shouldBeBlank &&
|
||||
!this.loadTimer;
|
||||
|
||||
@ -525,7 +520,7 @@ class AsyncTabSwitcher {
|
||||
// We've decided to try to load requestedTab.
|
||||
loadRequestedTab() {
|
||||
this.assert(!this.loadTimer);
|
||||
this.assert(!this.minimizedOrFullyOccluded);
|
||||
this.assert(!this.windowHidden);
|
||||
|
||||
// loadingTab can be non-null here if we timed out loading the current tab.
|
||||
// In that case we just overwrite it with a different tab; it's had its chance.
|
||||
@ -553,7 +548,7 @@ class AsyncTabSwitcher {
|
||||
canCheckDocShellState &&
|
||||
state == this.STATE_LOADED &&
|
||||
!browser.docShellIsActive &&
|
||||
!this.minimizedOrFullyOccluded
|
||||
!this.windowHidden
|
||||
) {
|
||||
browser.docShellIsActive = true;
|
||||
this.logState(
|
||||
@ -635,7 +630,7 @@ class AsyncTabSwitcher {
|
||||
let stateOfRequestedTab = this.getTabState(this.requestedTab);
|
||||
if (
|
||||
!this.loadTimer &&
|
||||
!this.minimizedOrFullyOccluded &&
|
||||
!this.windowHidden &&
|
||||
(stateOfRequestedTab == this.STATE_UNLOADED ||
|
||||
stateOfRequestedTab == this.STATE_UNLOADING ||
|
||||
this.warmingTabs.has(this.requestedTab))
|
||||
@ -854,8 +849,8 @@ class AsyncTabSwitcher {
|
||||
this.lastVisibleTab = null;
|
||||
}
|
||||
|
||||
onSizeModeOrOcclusionStateChange() {
|
||||
if (this.minimizedOrFullyOccluded) {
|
||||
onVisibilityChange() {
|
||||
if (this.windowHidden) {
|
||||
for (let [tab, state] of this.tabState) {
|
||||
if (!this.shouldDeactivateDocShell(tab.linkedBrowser)) {
|
||||
continue;
|
||||
@ -962,7 +957,7 @@ class AsyncTabSwitcher {
|
||||
// crashed, already visible, or already requested, warming
|
||||
// up the tab makes no sense.
|
||||
if (
|
||||
this.minimizedOrFullyOccluded ||
|
||||
this.windowHidden ||
|
||||
!tab.linkedPanel ||
|
||||
tab.closing ||
|
||||
!tab.linkedBrowser.isRemoteBrowser ||
|
||||
@ -1118,9 +1113,8 @@ class AsyncTabSwitcher {
|
||||
case "TabRemotenessChange":
|
||||
this.onRemotenessChange(event.target);
|
||||
break;
|
||||
case "sizemodechange":
|
||||
case "occlusionstatechange":
|
||||
this.onSizeModeOrOcclusionStateChange();
|
||||
case "visibilitychange":
|
||||
this.onVisibilityChange();
|
||||
break;
|
||||
case "SwapDocShells":
|
||||
this.onSwapDocShells(event.originalTarget, event.detail);
|
||||
|
@ -116,8 +116,7 @@ let NewTabPagePreloading = {
|
||||
!this.enabled ||
|
||||
window.gBrowser.preloadedBrowser ||
|
||||
!window.toolbar.visible ||
|
||||
window.windowState == window.STATE_MINIMIZED ||
|
||||
window.isFullyOccluded
|
||||
window.document.hidden
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
[onvisibilitychange.html]
|
||||
bug: Previously-running minimize test leaves window hidden
|
||||
expected:
|
||||
if os == "linux": TIMEOUT
|
||||
[onvisibilitychange attribute is a proper event handler]
|
||||
expected:
|
||||
if os == "linux": NOTRUN
|
@ -0,0 +1,12 @@
|
||||
[test_child_document.html]
|
||||
[document.visibilityState for frame with no style attribute == visible]
|
||||
expected:
|
||||
if os == "linux": FAIL
|
||||
|
||||
[document.visibilityState for frame with 'display:none' style == visible]
|
||||
expected:
|
||||
if os == "linux": FAIL
|
||||
|
||||
[document.visibilityState for frame with 'visibility:hidden' style == visible]
|
||||
expected:
|
||||
if os == "linux": FAIL
|
@ -0,0 +1,4 @@
|
||||
[unload-bubbles.html]
|
||||
expected: TIMEOUT
|
||||
[visibilitychange event bubbles when fired on unload]
|
||||
expected: TIMEOUT
|
@ -0,0 +1,4 @@
|
||||
[unload.html]
|
||||
expected: TIMEOUT
|
||||
[visibilitychange fires on unload]
|
||||
expected: TIMEOUT
|
@ -16,13 +16,17 @@
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<script class="testbody">
|
||||
<![CDATA[
|
||||
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
let gWindow = null;
|
||||
|
||||
const kIsLinux = navigator.platform.includes("Lin");
|
||||
// On Linux sizemode changes might be async.
|
||||
const kAsyncChanges = kIsLinux;
|
||||
|
||||
let gSizeModeDidChange = false;
|
||||
let gSizeModeDidChangeTo = 0;
|
||||
|
||||
@ -31,11 +35,28 @@ function sizemodeChanged(e) {
|
||||
gSizeModeDidChangeTo = gWindow.windowState;
|
||||
}
|
||||
|
||||
function expectSizeModeChange(newMode, duringActionCallback) {
|
||||
async function expectSizeModeChange(newMode, duringActionCallback) {
|
||||
gSizeModeDidChange = false;
|
||||
|
||||
let promise = null;
|
||||
if (kAsyncChanges) {
|
||||
if (newMode) {
|
||||
promise = new Promise(resolve => {
|
||||
gWindow.addEventListener("sizemodechange", function() {
|
||||
SimpleTest.executeSoon(resolve);
|
||||
}, { once: true })
|
||||
});
|
||||
} else {
|
||||
promise = new Promise(SimpleTest.executeSoon);
|
||||
}
|
||||
}
|
||||
|
||||
duringActionCallback();
|
||||
|
||||
if (promise) {
|
||||
await promise;
|
||||
}
|
||||
|
||||
if (newMode == 0) {
|
||||
// No change should have taken place, no event should have fired.
|
||||
ok(!gSizeModeDidChange, "No sizemodechange event should have fired.");
|
||||
@ -43,15 +64,17 @@ function expectSizeModeChange(newMode, duringActionCallback) {
|
||||
// Size mode change event was expected to fire.
|
||||
ok(gSizeModeDidChange, "A sizemodechanged event should have fired.");
|
||||
is(gSizeModeDidChangeTo, newMode, "The new sizemode should have the expected value.");
|
||||
const expectedHidden = newMode == gWindow.STATE_MINIMIZED || gWindow.isFullyOccluded;
|
||||
if (gWindow.document.hidden != expectedHidden) {
|
||||
await new Promise(resolve => {
|
||||
gWindow.addEventListener("visibilitychange", resolve, { once: true });
|
||||
});
|
||||
}
|
||||
is(gWindow.document.hidden, expectedHidden, "Should be inactive if minimized or occluded.");
|
||||
}
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
if (navigator.platform.includes("Lin")) {
|
||||
ok(true, "This test is disabled on Linux because it expects window sizemode changes to be synchronous (which is not the case on Linux).");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
};
|
||||
openWindow();
|
||||
}
|
||||
|
||||
@ -61,33 +84,38 @@ function openWindow() {
|
||||
SimpleTest.waitForFocus(runTest, gWindow);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
async function runTest() {
|
||||
if (kIsLinux) {
|
||||
todo(false, "Test times out on automation because bug 1780212");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
// Install event handler.
|
||||
gWindow.addEventListener("sizemodechange", sizemodeChanged);
|
||||
|
||||
// Run tests.
|
||||
expectSizeModeChange(gWindow.STATE_MINIMIZED, function () {
|
||||
await expectSizeModeChange(gWindow.STATE_MINIMIZED, function () {
|
||||
gWindow.minimize();
|
||||
});
|
||||
|
||||
expectSizeModeChange(gWindow.STATE_NORMAL, function () {
|
||||
await expectSizeModeChange(gWindow.STATE_NORMAL, function () {
|
||||
gWindow.restore();
|
||||
});
|
||||
|
||||
expectSizeModeChange(gWindow.STATE_MAXIMIZED, function () {
|
||||
await expectSizeModeChange(gWindow.STATE_MAXIMIZED, function () {
|
||||
gWindow.maximize();
|
||||
});
|
||||
|
||||
expectSizeModeChange(gWindow.STATE_NORMAL, function () {
|
||||
await expectSizeModeChange(gWindow.STATE_NORMAL, function () {
|
||||
gWindow.restore();
|
||||
});
|
||||
|
||||
// Normal window resizing shouldn't fire a sizemodechanged event, bug 715867.
|
||||
expectSizeModeChange(0, function () {
|
||||
await expectSizeModeChange(0, function () {
|
||||
gWindow.resizeTo(gWindow.outerWidth + 10, gWindow.outerHeight);
|
||||
});
|
||||
|
||||
expectSizeModeChange(0, function () {
|
||||
await expectSizeModeChange(0, function () {
|
||||
gWindow.resizeTo(gWindow.outerWidth, gWindow.outerHeight + 10);
|
||||
});
|
||||
|
||||
|
@ -2822,6 +2822,8 @@ void AppWindow::SizeModeChanged(nsSizeMode sizeMode) {
|
||||
}
|
||||
mWindow->SetSizeMode(sizeMode);
|
||||
|
||||
RecomputeBrowsingContextVisibility();
|
||||
|
||||
// Persist mode, but not immediately, because in many (all?)
|
||||
// cases this will merge with the similar call in NS_SIZE and
|
||||
// write the attribute values only once.
|
||||
@ -2927,13 +2929,33 @@ void AppWindow::MacFullscreenMenubarOverlapChanged(
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::RecomputeBrowsingContextVisibility() {
|
||||
if (!mDocShell) {
|
||||
return;
|
||||
}
|
||||
if (RefPtr bc = mDocShell->GetBrowsingContext()) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
mDocShell->GetMainWidget(getter_AddRefs(widget));
|
||||
const bool isActive = [&] {
|
||||
if (!widget) {
|
||||
return false;
|
||||
}
|
||||
return widget->SizeMode() != nsSizeMode_Minimized &&
|
||||
!widget->IsFullyOccluded();
|
||||
}();
|
||||
bc->SetIsActive(isActive, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
void AppWindow::OcclusionStateChanged(bool aIsFullyOccluded) {
|
||||
nsCOMPtr<nsPIDOMWindowOuter> ourWindow =
|
||||
mDocShell ? mDocShell->GetWindow() : nullptr;
|
||||
if (ourWindow) {
|
||||
if (!mDocShell) {
|
||||
return;
|
||||
}
|
||||
RecomputeBrowsingContextVisibility();
|
||||
if (RefPtr win = mDocShell->GetWindow()) {
|
||||
// And always fire a user-defined occlusionstatechange event on the window
|
||||
ourWindow->DispatchCustomEvent(u"occlusionstatechange"_ns,
|
||||
ChromeOnlyDispatch::eYes);
|
||||
win->DispatchCustomEvent(u"occlusionstatechange"_ns,
|
||||
ChromeOnlyDispatch::eYes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,7 @@ class AppWindow final : public nsIBaseWindow,
|
||||
MOZ_CAN_RUN_SCRIPT void MacFullscreenMenubarOverlapChanged(
|
||||
mozilla::DesktopCoord aOverlapAmount);
|
||||
MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded);
|
||||
void RecomputeBrowsingContextVisibility();
|
||||
MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed();
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
|
||||
|
Loading…
Reference in New Issue
Block a user