wayland: Make fullscreen mode updates async

Currently, the fullscreen state is update synchronously, but it needs to
be done in asynchronous fashion.

This change removes some tests as they don't add any value, testFullscreen()
covers them all.
This commit is contained in:
Vlad Zahorodnii 2021-05-01 18:07:11 +03:00
parent 62500acd1a
commit a0fc0277a7
6 changed files with 26 additions and 137 deletions

View file

@ -68,9 +68,7 @@ private Q_SLOTS:
void testFullscreen_data();
void testFullscreen();
void testFullscreenRestore();
void testUserCanSetFullscreen();
void testUserSetFullscreen();
void testMaximizeHorizontal();
void testMaximizeVertical();
@ -432,13 +430,8 @@ void TestXdgShellClient::testFullscreen()
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
Test::render(surface.data(), configureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
#if 0 // TODO: Uncomment when full screen state updates are truly asynchronous.
QVERIFY(fullScreenChangedSpy.wait());
QCOMPARE(fullScreenChangedSpy.count(), 1);
#else
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(fullScreenChangedSpy.count(), 1);
#endif
QVERIFY(client->isFullScreen());
QVERIFY(!client->isDecorated());
QCOMPARE(client->layer(), ActiveLayer);
@ -455,13 +448,8 @@ void TestXdgShellClient::testFullscreen()
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
Test::render(surface.data(), configureRequestedSpy.last().at(0).value<QSize>(), Qt::blue);
#if 0 // TODO: Uncomment when full screen state updates are truly asynchronous.
QVERIFY(fullScreenChangedSpy.wait());
QCOMPARE(fullScreenChangedSpy.count(), 2);
#else
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(fullScreenChangedSpy.count(), 2);
#endif
QCOMPARE(client->clientSize(), QSize(100, 50));
QVERIFY(!client->isFullScreen());
QCOMPARE(client->isDecorated(), decoMode == ServerSideDecoration::Mode::Server);
@ -472,58 +460,6 @@ void TestXdgShellClient::testFullscreen()
QVERIFY(Test::waitForWindowDestroyed(client));
}
void TestXdgShellClient::testFullscreenRestore()
{
// this test verifies that windows created fullscreen can be later properly restored
QScopedPointer<Surface> surface(Test::createSurface());
XdgShellSurface *xdgShellSurface = Test::createXdgShellStableSurface(surface.data(), surface.data(), Test::CreationSetup::CreateOnly);
QSignalSpy configureRequestedSpy(xdgShellSurface, &XdgShellSurface::configureRequested);
// fullscreen the window
xdgShellSurface->setFullscreen(true);
surface->commit(Surface::CommitFlag::None);
configureRequestedSpy.wait();
QCOMPARE(configureRequestedSpy.count(), 1);
const auto size = configureRequestedSpy.first()[0].value<QSize>();
const auto state = configureRequestedSpy.first()[1].value<KWayland::Client::XdgShellSurface::States>();
QCOMPARE(size, screens()->size(0));
QVERIFY(state & KWayland::Client::XdgShellSurface::State::Fullscreen);
xdgShellSurface->ackConfigure(configureRequestedSpy.first()[2].toUInt());
auto c = Test::renderAndWaitForShown(surface.data(), size, Qt::blue);
QVERIFY(c);
QVERIFY(c->isFullScreen());
configureRequestedSpy.wait(100);
QSignalSpy fullscreenChangedSpy(c, &AbstractClient::fullScreenChanged);
QVERIFY(fullscreenChangedSpy.isValid());
QSignalSpy frameGeometryChangedSpy(c, &AbstractClient::frameGeometryChanged);
QVERIFY(frameGeometryChangedSpy.isValid());
// swap back to normal
configureRequestedSpy.clear();
xdgShellSurface->setFullscreen(false);
QVERIFY(fullscreenChangedSpy.wait());
QVERIFY(configureRequestedSpy.wait());
QCOMPARE(configureRequestedSpy.last().first().toSize(), QSize(0, 0));
QVERIFY(!c->isFullScreen());
for (const auto &it: configureRequestedSpy) {
xdgShellSurface->ackConfigure(it[2].toUInt());
}
Test::render(surface.data(), QSize(100, 50), Qt::red);
QVERIFY(frameGeometryChangedSpy.wait());
QCOMPARE(frameGeometryChangedSpy.count(), 1);
QVERIFY(!c->isFullScreen());
QCOMPARE(c->frameGeometry().size(), QSize(100, 50));
}
void TestXdgShellClient::testUserCanSetFullscreen()
{
QScopedPointer<Surface> surface(Test::createSurface());
@ -535,59 +471,6 @@ void TestXdgShellClient::testUserCanSetFullscreen()
QVERIFY(c->userCanSetFullScreen());
}
void TestXdgShellClient::testUserSetFullscreen()
{
QScopedPointer<Surface> surface(Test::createSurface());
QScopedPointer<XdgShellSurface> shellSurface(Test::createXdgShellStableSurface(
surface.data(), surface.data(), Test::CreationSetup::CreateOnly));
QVERIFY(!shellSurface.isNull());
// wait for the initial configure event
QSignalSpy configureRequestedSpy(shellSurface.data(), &XdgShellSurface::configureRequested);
QVERIFY(configureRequestedSpy.isValid());
surface->commit(Surface::CommitFlag::None);
QVERIFY(configureRequestedSpy.wait());
QCOMPARE(configureRequestedSpy.count(), 1);
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
QVERIFY(c);
QVERIFY(c->isActive());
QVERIFY(!c->isFullScreen());
// The client gets activated, which gets another configure event. Though that's not relevant to the test
configureRequestedSpy.wait(10);
QSignalSpy fullscreenChangedSpy(c, &AbstractClient::fullScreenChanged);
QVERIFY(fullscreenChangedSpy.isValid());
c->setFullScreen(true);
QCOMPARE(c->isFullScreen(), true);
configureRequestedSpy.clear();
QVERIFY(configureRequestedSpy.wait());
QCOMPARE(configureRequestedSpy.count(), 1);
QCOMPARE(configureRequestedSpy.first().at(0).toSize(), screens()->size(0));
const auto states = configureRequestedSpy.first().at(1).value<KWayland::Client::XdgShellSurface::States>();
QVERIFY(states.testFlag(KWayland::Client::XdgShellSurface::State::Fullscreen));
QVERIFY(states.testFlag(KWayland::Client::XdgShellSurface::State::Activated));
QVERIFY(!states.testFlag(KWayland::Client::XdgShellSurface::State::Maximized));
QVERIFY(!states.testFlag(KWayland::Client::XdgShellSurface::State::Resizing));
QCOMPARE(fullscreenChangedSpy.count(), 1);
QVERIFY(c->isFullScreen());
shellSurface->ackConfigure(configureRequestedSpy.first().at(2).value<quint32>());
// unset fullscreen again
c->setFullScreen(false);
QCOMPARE(c->isFullScreen(), false);
configureRequestedSpy.clear();
QVERIFY(configureRequestedSpy.wait());
QCOMPARE(configureRequestedSpy.count(), 1);
QCOMPARE(configureRequestedSpy.first().at(0).toSize(), QSize(100, 50));
QVERIFY(!configureRequestedSpy.first().at(1).value<KWayland::Client::XdgShellSurface::States>().testFlag(KWayland::Client::XdgShellSurface::State::Fullscreen));
QCOMPARE(fullscreenChangedSpy.count(), 2);
QVERIFY(!c->isFullScreen());
}
void TestXdgShellClient::testMaximizedToFullscreen_data()
{
QTest::addColumn<ServerSideDecoration::Mode>("decoMode");
@ -660,12 +543,8 @@ void TestXdgShellClient::testMaximizedToFullscreen()
shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value<quint32>());
Test::render(surface.data(), configureRequestedSpy.last().at(0).value<QSize>(), Qt::red);
#if 0 // TODO: Uncomment when full screen changes are truly asynchronous.
QVERIFY(fullScreenChangedSpy.wait());
QCOMPARE(fullScreenChangedSpy.count(), 1);
#else
QTRY_COMPARE(fullscreenChangedSpy.count(), 1);
#endif
QVERIFY(fullscreenChangedSpy.wait());
QCOMPARE(fullscreenChangedSpy.count(), 1);
QCOMPARE(client->maximizeMode(), MaximizeFull);
QVERIFY(client->isFullScreen());
QVERIFY(!client->isDecorated());

View file

@ -3615,6 +3615,11 @@ bool AbstractClient::isFullScreen() const
return false;
}
bool AbstractClient::isRequestedFullScreen() const
{
return isFullScreen();
}
/**
* Returns whether requests initiated by the user to enter or leave full screen mode are honored.
*

View file

@ -419,6 +419,7 @@ public:
virtual void hideClient(bool hide) = 0;
virtual bool isFullScreenable() const;
virtual bool isFullScreen() const;
virtual bool isRequestedFullScreen() const;
// TODO: remove boolean trap
virtual AbstractClient *findModal(bool allow_itself = false) = 0;
virtual bool isTransient() const;

View file

@ -718,7 +718,7 @@ void Workspace::addShellClient(AbstractClient *client)
if (client->isPlaceable()) {
const QRect area = clientArea(PlacementArea, Screens::self()->current(), client->desktop());
bool placementDone = false;
if (client->isFullScreen()) {
if (client->isRequestedFullScreen()) {
placementDone = true;
}
if (client->maximizeMode() == MaximizeMode::MaximizeFull) {

View file

@ -457,9 +457,14 @@ bool XdgToplevelClient::isFullScreen() const
return m_isFullScreen;
}
bool XdgToplevelClient::isRequestedFullScreen() const
{
return m_isRequestedFullScreen;
}
bool XdgToplevelClient::isMovable() const
{
if (isFullScreen()) {
if (isRequestedFullScreen()) {
return false;
}
if (isSpecialWindow() && !isSplash() && !isToolbar()) {
@ -484,7 +489,7 @@ bool XdgToplevelClient::isMovableAcrossScreens() const
bool XdgToplevelClient::isResizable() const
{
if (isFullScreen()) {
if (isRequestedFullScreen()) {
return false;
}
if (isSpecialWindow() || isSplash() || isToolbar()) {
@ -577,7 +582,7 @@ bool XdgToplevelClient::noBorder() const
if (m_serverDecoration) {
switch (m_serverDecoration->mode()) {
case ServerSideDecorationManagerInterface::Mode::Server:
return m_userNoBorder || isFullScreen();
return m_userNoBorder || isRequestedFullScreen();
case ServerSideDecorationManagerInterface::Mode::Client:
case ServerSideDecorationManagerInterface::Mode::None:
return true;
@ -587,7 +592,7 @@ bool XdgToplevelClient::noBorder() const
switch (m_xdgDecoration->preferredMode()) {
case XdgToplevelDecorationV1Interface::Mode::Server:
case XdgToplevelDecorationV1Interface::Mode::Undefined:
return !Decoration::DecorationBridge::hasPlugin() || m_userNoBorder || isFullScreen();
return !Decoration::DecorationBridge::hasPlugin() || m_userNoBorder || isRequestedFullScreen();
case XdgToplevelDecorationV1Interface::Mode::Client:
return true;
}
@ -791,7 +796,7 @@ void XdgToplevelClient::doSetActive()
void XdgToplevelClient::doSetFullScreen()
{
if (isFullScreen()) {
if (isRequestedFullScreen()) {
m_requestedStates |= XdgToplevelInterface::State::FullScreen;
} else {
m_requestedStates &= ~XdgToplevelInterface::State::FullScreen;
@ -1223,7 +1228,7 @@ void XdgToplevelClient::initialize()
RuleBook::self()->discardUsed(this, false); // Remove Apply Now rules.
updateWindowRules(Rules::All);
}
if (isFullScreen()) {
if (isRequestedFullScreen()) {
needsPlacement = false;
}
if (needsPlacement) {
@ -1253,7 +1258,9 @@ void XdgToplevelClient::updateFullScreenMode(bool set)
if (m_isFullScreen == set) {
return;
}
StackingUpdatesBlocker blocker1(workspace());
m_isFullScreen = set;
updateLayer();
updateWindowRules(Rules::Fullscreen);
emit fullScreenChanged();
}
@ -1527,7 +1534,7 @@ void XdgToplevelClient::setFullScreen(bool set, bool user)
{
set = rules()->checkFullScreen(set);
const bool wasFullscreen = isFullScreen();
const bool wasFullscreen = isRequestedFullScreen();
if (wasFullscreen == set) {
return;
}
@ -1543,18 +1550,16 @@ void XdgToplevelClient::setFullScreen(bool set, bool user)
} else {
setFullscreenGeometryRestore(frameGeometry());
}
m_isFullScreen = set;
m_isRequestedFullScreen = set;
if (set) {
workspace()->raiseClient(this);
}
StackingUpdatesBlocker blocker1(workspace());
GeometryUpdatesBlocker blocker2(this);
if (set) {
dontMoveResize();
}
workspace()->updateClientLayer(this); // active fullscreens get different layer
updateDecoration(false, false);
if (set) {
@ -1576,9 +1581,6 @@ void XdgToplevelClient::setFullScreen(bool set, bool user)
}
doSetFullScreen();
updateWindowRules(Rules::Fullscreen|Rules::Position|Rules::Size);
emit fullScreenChanged();
}
/**

View file

@ -126,6 +126,7 @@ public:
QSize minSize() const override;
QSize maxSize() const override;
bool isFullScreen() const override;
bool isRequestedFullScreen() const override;
bool isMovableAcrossScreens() const override;
bool isMovable() const override;
bool isResizable() const override;
@ -215,6 +216,7 @@ private:
MaximizeMode m_maximizeMode = MaximizeRestore;
MaximizeMode m_requestedMaximizeMode = MaximizeRestore;
bool m_isFullScreen = false;
bool m_isRequestedFullScreen = false;
bool m_isInitialized = false;
bool m_userNoBorder = false;
bool m_isTransient = false;