From a0fc0277a7e5efc9b053909eb54a3eed0a3965aa Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 1 May 2021 18:07:11 +0300 Subject: [PATCH] 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. --- autotests/integration/xdgshellclient_test.cpp | 125 +----------------- src/abstract_client.cpp | 5 + src/abstract_client.h | 1 + src/workspace.cpp | 2 +- src/xdgshellclient.cpp | 28 ++-- src/xdgshellclient.h | 2 + 6 files changed, 26 insertions(+), 137 deletions(-) diff --git a/autotests/integration/xdgshellclient_test.cpp b/autotests/integration/xdgshellclient_test.cpp index 53f698f1f5..36e64ddc03 100644 --- a/autotests/integration/xdgshellclient_test.cpp +++ b/autotests/integration/xdgshellclient_test.cpp @@ -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()); Test::render(surface.data(), configureRequestedSpy.last().at(0).value(), 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()); Test::render(surface.data(), configureRequestedSpy.last().at(0).value(), 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(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(); - const auto state = configureRequestedSpy.first()[1].value(); - - 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(Test::createSurface()); @@ -535,59 +471,6 @@ void TestXdgShellClient::testUserCanSetFullscreen() QVERIFY(c->userCanSetFullScreen()); } -void TestXdgShellClient::testUserSetFullscreen() -{ - QScopedPointer surface(Test::createSurface()); - QScopedPointer 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()); - 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(); - 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()); - - // 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().testFlag(KWayland::Client::XdgShellSurface::State::Fullscreen)); - QCOMPARE(fullscreenChangedSpy.count(), 2); - QVERIFY(!c->isFullScreen()); -} - void TestXdgShellClient::testMaximizedToFullscreen_data() { QTest::addColumn("decoMode"); @@ -660,12 +543,8 @@ void TestXdgShellClient::testMaximizedToFullscreen() shellSurface->ackConfigure(configureRequestedSpy.last().at(2).value()); Test::render(surface.data(), configureRequestedSpy.last().at(0).value(), 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()); diff --git a/src/abstract_client.cpp b/src/abstract_client.cpp index 4d14fbbabd..720b3e215b 100644 --- a/src/abstract_client.cpp +++ b/src/abstract_client.cpp @@ -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. * diff --git a/src/abstract_client.h b/src/abstract_client.h index 7be88fdcc2..55ffe7c639 100644 --- a/src/abstract_client.h +++ b/src/abstract_client.h @@ -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; diff --git a/src/workspace.cpp b/src/workspace.cpp index 4924072784..78a865e8f9 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -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) { diff --git a/src/xdgshellclient.cpp b/src/xdgshellclient.cpp index 02f5c7775a..f1468284f0 100644 --- a/src/xdgshellclient.cpp +++ b/src/xdgshellclient.cpp @@ -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(); } /** diff --git a/src/xdgshellclient.h b/src/xdgshellclient.h index 752cf2a3a2..233d3c91ca 100644 --- a/src/xdgshellclient.h +++ b/src/xdgshellclient.h @@ -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;