Skip to content

Commit

Permalink
Bug 1823284 - Use SizeModeChanged notification to handle fullscreen…
Browse files Browse the repository at this point in the history
… change; r=geckoview-reviewers,rkraesig,stransky,bradwerth,smaug,m_kato

Depends on D175213

Differential Revision: https://phabricator.services.mozilla.com/D175215
  • Loading branch information
EdgarChen committed Apr 23, 2023
1 parent 65bc134 commit 58bec56
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 82 deletions.
1 change: 1 addition & 0 deletions dom/base/test/fullscreen/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ support-files =
file_fullscreen-bug-1798219.html
file_fullscreen-bug-1798219-2.html
[browser_fullscreen-window-open-race.js]
[browser_fullscreen-sizemode.js]
225 changes: 225 additions & 0 deletions dom/base/test/fullscreen/browser_fullscreen-sizemode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const isMac = AppConstants.platform == "macosx";
const isWin = AppConstants.platform == "win";

async function waitForSizeMode(aWindow, aSizeMode) {
await BrowserTestUtils.waitForEvent(aWindow, "sizemodechange", false, () => {
return aWindow.windowState === aSizeMode;
});
const expectedHidden =
aSizeMode == aWindow.STATE_MINIMIZED || aWindow.isFullyOccluded;
if (aWindow.document.hidden != expectedHidden) {
await BrowserTestUtils.waitForEvent(aWindow, "visibilitychange");
}
is(
aWindow.document.hidden,
expectedHidden,
"Should be inactive if minimized or occluded"
);
}

async function checkSizeModeAndFullscreenState(
aWindow,
aSizeMode,
aFullscreen,
aFullscreenEventShouldHaveFired,
aStepFun
) {
let promises = [];
if (aWindow.windowState != aSizeMode) {
promises.push(waitForSizeMode(aWindow, aSizeMode));
}
if (aFullscreenEventShouldHaveFired) {
promises.push(
BrowserTestUtils.waitForEvent(
aWindow,
aFullscreen ? "willenterfullscreen" : "willexitfullscreen"
)
);
promises.push(BrowserTestUtils.waitForEvent(aWindow, "fullscreen"));
}

// Add listener for unexpected event.
let unexpectedEventListener = aEvent => {
ok(false, `should not receive ${aEvent.type} event`);
};
if (aFullscreenEventShouldHaveFired) {
aWindow.addEventListener(
aFullscreen ? "willexitfullscreen" : "willenterfullscreen",
unexpectedEventListener
);
} else {
aWindow.addEventListener("willenterfullscreen", unexpectedEventListener);
aWindow.addEventListener("willexitfullscreen", unexpectedEventListener);
aWindow.addEventListener("fullscreen", unexpectedEventListener);
}

let eventPromise = Promise.all(promises);
aStepFun();
await eventPromise;

// Check SizeMode.
is(
aWindow.windowState,
aSizeMode,
"The new sizemode should have the expected value"
);
// Check Fullscreen state.
is(
aWindow.fullScreen,
aFullscreen,
`chrome window should ${aFullscreen ? "be" : "not be"} in fullscreen`
);
is(
aWindow.document.documentElement.hasAttribute("inFullscreen"),
aFullscreen,
`chrome documentElement should ${
aFullscreen ? "have" : "not have"
} inFullscreen attribute`
);

// Remove listener for unexpected event.
if (aFullscreenEventShouldHaveFired) {
aWindow.removeEventListener(
aFullscreen ? "willexitfullscreen" : "willenterfullscreen",
unexpectedEventListener
);
} else {
aWindow.removeEventListener("willenterfullscreen", unexpectedEventListener);
aWindow.removeEventListener("willexitfullscreen", unexpectedEventListener);
aWindow.removeEventListener("fullscreen", unexpectedEventListener);
}
}

async function restoreWindowToNormal(aWindow) {
while (aWindow.windowState != aWindow.STATE_NORMAL) {
info(`Try to restore window with state ${aWindow.windowState} to normal`);
let eventPromise = BrowserTestUtils.waitForEvent(aWindow, "sizemodechange");
aWindow.restore();
await eventPromise;
info(`Window is now in state ${aWindow.windowState}`);
}
}

add_task(async function test_fullscreen_restore() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await restoreWindowToNormal(win);

info("Enter fullscreen");
await checkSizeModeAndFullscreenState(
win,
win.STATE_FULLSCREEN,
true,
true,
() => {
win.fullScreen = true;
}
);

info("Restore window");
await checkSizeModeAndFullscreenState(
win,
win.STATE_NORMAL,
false,
true,
() => {
win.restore();
}
);

await BrowserTestUtils.closeWindow(win);
});

// This test only enable on Windows because:
// - Test gets intermittent timeout on macOS, see bug 1828848.
// - Restoring a fullscreen window on GTK doesn't return it to the previous
// sizemode, see bug 1828837.
if (isWin) {
add_task(async function test_maximize_fullscreen_restore() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await restoreWindowToNormal(win);

info("Maximize window");
await checkSizeModeAndFullscreenState(
win,
win.STATE_MAXIMIZED,
false,
false,
() => {
win.maximize();
}
);

info("Enter fullscreen");
await checkSizeModeAndFullscreenState(
win,
win.STATE_FULLSCREEN,
true,
true,
() => {
win.fullScreen = true;
}
);

info("Restore window");
await checkSizeModeAndFullscreenState(
win,
win.STATE_MAXIMIZED,
false,
true,
() => {
win.restore();
}
);

await BrowserTestUtils.closeWindow(win);
});
}

// Restoring a minimized window on macOS doesn't return it to the previous
// sizemode, see bug 1828706.
if (!isMac) {
add_task(async function test_fullscreen_minimize_restore() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await restoreWindowToNormal(win);

info("Enter fullscreen");
await checkSizeModeAndFullscreenState(
win,
win.STATE_FULLSCREEN,
true,
true,
() => {
win.fullScreen = true;
}
);

info("Minimize window");
await checkSizeModeAndFullscreenState(
win,
win.STATE_MINIMIZED,
true,
false,
() => {
win.minimize();
}
);

info("Restore window");
await checkSizeModeAndFullscreenState(
win,
win.STATE_FULLSCREEN,
true,
false,
() => {
win.restore();
}
);

await BrowserTestUtils.closeWindow(win);
});
}
7 changes: 1 addition & 6 deletions widget/android/nsWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2426,19 +2426,14 @@ nsresult nsWindow::MakeFullScreen(bool aFullScreen) {
return NS_ERROR_NOT_AVAILABLE;
}

nsIWidgetListener* listener = GetWidgetListener();
if (listener) {
listener->FullscreenWillChange(aFullScreen);
}

mIsFullScreen = aFullScreen;
mAndroidView->mEventDispatcher->Dispatch(
aFullScreen ? u"GeckoView:FullScreenEnter" : u"GeckoView:FullScreenExit");

nsIWidgetListener* listener = GetWidgetListener();
if (listener) {
mSizeMode = mIsFullScreen ? nsSizeMode_Fullscreen : nsSizeMode_Normal;
listener->SizeModeChanged(mSizeMode);
listener->FullscreenChanged(mIsFullScreen);
}
return NS_OK;
}
Expand Down
20 changes: 0 additions & 20 deletions widget/cocoa/nsCocoaWindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1634,17 +1634,9 @@ static bool AlwaysUsesNativeFullScreen() {
// happens.
mUpdateFullscreenOnResize =
Some(aFullscreen ? TransitionType::Fullscreen : TransitionType::Windowed);

if (mWidgetListener) {
mWidgetListener->FullscreenWillChange(aFullscreen);
}
}

void nsCocoaWindow::CocoaWindowDidFailFullscreen(bool aAttemptedFullscreen) {
if (mWidgetListener) {
mWidgetListener->FullscreenWillChange(!aAttemptedFullscreen);
}

// If we already updated our fullscreen state due to a resize, we need to update it again.
if (mUpdateFullscreenOnResize.isNothing()) {
UpdateFullscreenState(!aAttemptedFullscreen, true);
Expand All @@ -1669,10 +1661,6 @@ static bool AlwaysUsesNativeFullScreen() {

DispatchSizeModeEvent();

if (mWidgetListener) {
mWidgetListener->FullscreenChanged(aFullScreen);
}

// Notify the mainChildView with our new fullscreen state.
nsChildView* mainChildView = static_cast<nsChildView*>([[mWindow mainChildView] widget]);
if (mainChildView) {
Expand Down Expand Up @@ -1773,10 +1761,6 @@ static bool AlwaysUsesNativeFullScreen() {

case TransitionType::EmulatedFullscreen: {
if (!mInFullScreenMode) {
// This can be done synchronously.
if (mWidgetListener) {
mWidgetListener->FullscreenWillChange(true);
}
NSDisableScreenUpdates();
mSuppressSizeModeEvents = true;
// The order here matters. When we exit full screen mode, we need to show the
Expand All @@ -1798,10 +1782,6 @@ static bool AlwaysUsesNativeFullScreen() {
[mWindow toggleFullScreen:nil];
continue;
} else {
// This can be done synchronously.
if (mWidgetListener) {
mWidgetListener->FullscreenWillChange(false);
}
NSDisableScreenUpdates();
mSuppressSizeModeEvents = true;
// The order here matters. When we exit full screen mode, we need to show the
Expand Down
10 changes: 1 addition & 9 deletions widget/gtk/nsWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5240,15 +5240,7 @@ void nsWindow::OnWindowStateEvent(GtkWidget* aWidget,
LOG("\tTiled: %d\n", int(mIsTiled));

if (mWidgetListener && mSizeMode != oldSizeMode) {
if (mSizeMode == nsSizeMode_Fullscreen ||
oldSizeMode == nsSizeMode_Fullscreen) {
bool isFullscreen = mSizeMode == nsSizeMode_Fullscreen;
mWidgetListener->FullscreenWillChange(isFullscreen);
mWidgetListener->SizeModeChanged(mSizeMode);
mWidgetListener->FullscreenChanged(isFullscreen);
} else {
mWidgetListener->SizeModeChanged(mSizeMode);
}
mWidgetListener->SizeModeChanged(mSizeMode);
}

if (mDrawInTitlebar && mTransparencyBitmapForTitlebar) {
Expand Down
1 change: 0 additions & 1 deletion widget/headless/HeadlessWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,6 @@ nsresult HeadlessWidget::MakeFullScreen(bool aFullScreen) {
// resize events.
if (mWidgetListener) {
mWidgetListener->SizeModeChanged(mSizeMode);
mWidgetListener->FullscreenChanged(aFullScreen);
}

// Real widget backends don't seem to follow a common approach for
Expand Down
4 changes: 0 additions & 4 deletions widget/nsIWidgetListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ void nsIWidgetListener::DynamicToolbarMaxHeightChanged(ScreenIntCoord aHeight) {
void nsIWidgetListener::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {}
#endif

void nsIWidgetListener::FullscreenWillChange(bool aInFullscreen) {}

void nsIWidgetListener::FullscreenChanged(bool aInFullscreen) {}

void nsIWidgetListener::MacFullscreenMenubarOverlapChanged(
mozilla::DesktopCoord aOverlapAmount) {}

Expand Down
10 changes: 0 additions & 10 deletions widget/nsIWidgetListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,6 @@ class nsIWidgetListener {
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow);

/**
* Called when the window will enter or leave the fullscreen state.
*/
virtual void FullscreenWillChange(bool aInFullscreen);

/**
* Called when the window entered or left the fullscreen state.
*/
virtual void FullscreenChanged(bool aInFullscreen);

/**
* Called when the macOS titlebar is shown while in fullscreen.
*/
Expand Down
Loading

0 comments on commit 58bec56

Please sign in to comment.